É possível usar 2 comandos na -exec
parte de find
comando?
Eu tentei algo como:
find . -name "*" -exec chgrp -v new_group {} ; chmod -v 770 {} \;
e recebo:
find: argumento ausente para -exec
chmod: não é possível acessar {}: arquivo ou diretório não existe
chmod: não é possível acessar;: arquivo ou diretório não existe
Comentários
Resposta
Quanto ao comando find
, você também pode simplesmente adicionar mais -exec
comandos em uma linha:
find . -name "*" -exec chgrp -v new_group "{}" \; -exec chmod -v 770 "{}" \;
Observe que este comando é, em seu resultado t, equivalente a usar
chgrp -v arquivo new_group & & arquivo chmod -v 770
em cada arquivo.
Todos os find
“parâmetros como -name
, -exec
, -size
e assim por diante, são na verdade testes : find
continuará a executá-los um por um, desde que a cadeia inteira tenha sido avaliada como verdadeira . Portanto, cada comando -exec
consecutivo é executado apenas se os anteriores retornaram verdadeiro (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
testes independentemente dos resultados anteriores, seria necessário usar algo assim:
find . -name "*" \( -exec chgrp -v new_group {} \; -o -true \) -exec chmod -v 770 {} \;
Comentários
- +1: Sim, isso ' é a maneira mais elegante de fazer isso. Se você puder explicar por que usa
'{}'
(apóstrofos entre colchetes), visite: unix.stackexchange.com/q/ 8647/4485 - @user Infelizmente, não ' sei se ainda é necessário. Eu fiz alguns testes agora e não ' encontrei uma situação em que isso mudaria alguma coisa. Eu acho que ' é apenas " boas práticas " que vai morrer.
- As aspas são importantes para arquivos com espaços em seus nomes.
- @ naught101 Não, as aspas podem ser necessárias em alguns shells não padrão, como
fish
ecsh
, mas definitivamente não são necessários em shells tipo POSIX (sh
,dash
,bash
,zsh
,ksh
,yash
).
Resposta
find . -name "*" -exec sh -c "chgrp -v new_group "$0" ; chmod -v 770 "$0"" {} \;
Comentários
- @Gilles: As maravilhas de
-c
' s manuseio estranho de $ 0 me faz pensar que isso está errado toda vez que eu olho para ele, mas está definitivamente correto. - Eu gosto do shell explícito sendo definido …
- Esta resposta (e Giles ' s an swer) parece ser a melhor resposta para a pergunta dada a
sh -c
.
Resposta
Seu comando é primeiro analisado pelo shell em dois comandos separados por ;
, que é equivalente 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 você não se importa se o shell é 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 zero (que normalmente é o nome do shell ou script, mas isso não importa aqui), portanto, referido como "$0"
.
Você pode passar vários nomes de arquivo para o shell de uma vez e fazer o shell iterar por meio 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 "$@"
) são repetidos.
find . -name "*" -exec sh -c "for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done" _ {} +
Observe que desde o bash 4 ou em zsh, você não precisa encontrar nada aqui. No bash, execute shopt -s globstar
(coloque-o em ~/.bashrc
) para ativar o **/
que representa um diretório global recursivo. (Em zsh, isso é ativo o tempo todo.) Em seguida,
chgrp -v new_group -- **/*; chmod -v 770 -- **/*
ou se quiser que os arquivos sejam iterados na 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, em bash, primeiro defina GLOBIGNORE=.:..
; em zsh, use **/*(D)
como o padrão glob.
Comentários
- Esta resposta (e a resposta de Glenn ') parece ser a melhor resposta para a pergunta dada a
sh -c
. - Ambos
chgrp
echmod
tem um-R
opção para operação recursiva.
-name "*"
corresponde a todos os nomes, portanto, é ' um teste autônomo que pode ser removido. Além disso,chmod
echgrp
tem uma-R
opção para operação recursiva.