Como posso usar dois comandos bash em -exec do comando find?

30

É possível usar 2 comandos no comando -exec de find ?

Eu tentei algo como:

find . -name "*" -exec  chgrp -v new_group {}  ; chmod -v 770 {}  \;

e eu recebo:

find: missing argument to -exec
chmod: cannot access {}: No such file or directory
chmod: cannot access ;: No such file or directory

    
por Luc M 04.08.2011 / 20:51

3 respostas

42

Quanto ao comando find , você também pode adicionar mais comandos -exec seguidos:

find . -name "*" -exec chgrp -v new_group '{}' \; -exec chmod -v 770 '{}' \;

Note que este comando é, em seu resultado, equivalente ao uso de

chgrp -v new_group file && chmod -v 770 file

em cada arquivo.

Todos os parâmetros de find , como -name , -exec , -size e assim por diante, são realmente testes : find continuará a executá-los um por um desde que toda a cadeia tenha avaliado até true . Portanto, cada comando -exec consecutivo é executado somente se os anteriores retornarem true (ou seja, 0 status de saída dos comandos). Mas find também entende operadores lógicos como ou ( -o ) e não ( ! ). Portanto, para usar uma cadeia de -exec tests independentemente dos resultados anteriores, seria necessário usar algo assim:

find . -name "*" \( -exec chgrp -v new_group {} \; -o -exec chmod -v 770 {} \; \)
    
por 04.08.2011 / 22:24
16
find . -name "*" -exec sh -c 'chgrp -v new_group "$0" ; chmod -v 770 "$0"' {} \;
    
por 04.08.2011 / 21:02
12

Seu comando é primeiro analisado pelo shell em dois comandos separados por ; , o que equivale a uma nova linha:

find . -name "*" -exec chgrp -v new_group {}
chmod -v 770 {} \;

Se você deseja executar um comando shell, invoque um shell explicitamente com bash -c (ou sh -c se não se importar que o shell seja especificamente bash):

find . -name "*" -exec sh -c 'chgrp -v new_group "$0"; chmod -v 770 "$0"' {} \;

Observe o uso de {} como um argumento para o shell; é o argumento zeroth (que normalmente é o nome do shell ou script, mas isso não importa aqui), portanto, referenciado como "$0" .

Você pode passar vários nomes de arquivos para o shell de cada vez e fazer com que o shell faça uma iteração através deles, será mais rápido. Aqui eu passo _ como o nome do script e os seguintes argumentos são nomes de arquivos, que for x (um atalho para for x in "$@" ) itera.

find . -name "*" -exec sh -c 'for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done' _ {} +

Note que desde o bash 4, ou no zsh, você não precisa encontrar nada aqui. No bash, execute shopt -s globstar (coloque em seu ~/.bashrc ) para ativar **/ representando um glob de diretório recursivo. (Em zsh, isso fica ativo o tempo todo.) Então

chgrp -v new_group -- **/*; chmod -v 770 -- **/*

ou se você quiser que os arquivos sejam iterados em ordem

for x in **/*; do
  chgrp -v new_group -- "$x"
  chmod -v 770 -- "$x"
done

Uma diferença com o comando find é que o shell ignora arquivos de ponto (arquivos cujo nome começa com . ). Para incluí-los, no bash, primeiro defina GLOBIGNORE=.:.. ; em zsh, use **/*(D) como o padrão glob.

    
por 04.08.2011 / 21:35

Tags