É 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

  • Observe que -name "*" corresponde a todos os nomes, portanto, é ' um teste autônomo que pode ser removido. Além disso, chmod e chgrp tem uma -R opção para operação recursiva.

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 e csh, 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 e chmod tem um -R opção para operação recursiva.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *