Executando mais de um comando com xargs

3

É possível usar find + xargs para chamar mais de um comando? Eu estou tentando encontrar todos os arquivos cujo tamanho é maior que 100 caracteres. e menos de 1000 caracteres, altere suas permissões e imprima a lista de arquivos em arquivo. Eu posso fazer isso com exec, por exemplo

find . -maxdepth 1 -size +100c -size -1000c -exec chmod a+r {} \; -print > testfile

Mas existe alguma maneira de conseguir isso com xargs?

   find . -maxdepth 1 -size +100c -size -1000c -print0 | xargs -0 -I '{}' chmod a+r '{}' -print >testfile

a última impressão não será executada ou lançará um erro. Existe uma maneira de alcançá-lo com xargs?

    
por trolkura 13.12.2015 / 13:39

1 resposta

4

Você não precisa de nenhum dos GNUisms aqui (e provavelmente quer que um -mindepth 1 exclua . ), e você não precisa executar um chmod por arquivo:

find . ! -name . -prune ! -type l -size +100c -size -1000c -print \
  -exec chmod a+r {} + >testfile

(Eu também adicionei um ! -type l porque -size iria verificar o tamanho do link simbólico enquanto chmod mudaria as permissões do alvo do symlink para que ele não faz sentido considerar os links simbólicos. É provável que você queira ir além e considerar apenas arquivos regulares ( -type f ))

Isso funciona aqui porque chmod não produz nada em seu stdout (que de outra forma acabaria no testfile).

Mais geralmente, para evitar isso, você precisa fazer:

find . ! -name . -prune ! -type l -size +100c -size -1000c -print -exec sh -c '
  exec cmd-that-may-write-to-stdout "$@" >&3 3>&-' sh {} + 3>&1 > testfile 

Para que o stdout de find vá para testfile , mas o stdout de cmd-that-may-write-to-stdout vai para o stdout original antes do redirecionamento (conforme salvo com 3>&1 acima).

Note que no seu:

find . -maxdepth 1 -size +100c -size -1000c -exec chmod a+r {} \; -print > testfile

testfile conterá os arquivos para os quais chmod foi bem-sucedida (o -print sendo depois de -exec significa -exec é outra condição para esse -print e -exec terá êxito se o comando executado retornar com um status de saída diferente de zero).

Se você quisesse usar xargs (aqui usando a sintaxe do GNU), você poderia usar tee e processo de substituição:

 find . ! -name . -prune ! -type l -size +100c -size -1000c -print0 |
   tee >(tr '
(<that-code>) 3>&1 | cat
' '\n' > testfile) | xargs -r0 chmod a+r

Para salvar a saída de find com NULs, transformou-se em novas linhas em testfile . Observe, entretanto, que o comando tr está sendo executado em segundo plano. Seu shell aguardará xargs (pelo menos, a maioria dos shells também aguardará por tee e find ), mas não por tr . Portanto, há uma pequena chance de que tr tenha terminado de gravar dados em testfile quando o shell executar o próximo comando. Se for mais importante que o testfile seja totalmente escrito até então que todas as permissões sejam modificadas, talvez você queira trocar os comandos xargs e tr acima.

Outra opção é envolver todo o código acima em:

files=(./*(L+100L-1000^@))
chmod a+r $files
print -rl $files > testfile

Dessa forma, o shell aguardará cat e esse cat sairá somente quando todos os processos que tiverem esse descritor de arquivo 3 abrirem na extremidade de gravação do canal que ele lê (incluindo tr , find , tee , xargs ) foram encerrados.

Outra opção é usar zsh globs aqui:

find . ! -name . -prune ! -type l -size +100c -size -1000c -print \
  -exec chmod a+r {} + >testfile

Embora você possa encontrar erros muitos argumentos se a lista de arquivos for muito grande. find -exec + e xargs trabalham com isso executando vários comandos chmod , se necessário. Você pode usar zargs em zsh para isso.

    
por 13.12.2015 / 16:01

Tags