Como executo um comando em vários arquivos

13

Isso é bastante básico, tenho uma pasta com várias subpastas de arquivos JS e quero executar o compilador Clojure do Google em todos os arquivos dessas pastas. O comando para processar um único arquivo é o seguinte:

java -jar compiler.jar --js filename.js --js_output_file newfilename.js

Como modifico isso para ser executado em todos os arquivos JS na minha estrutura de diretórios?

Mataniko
fonte

Respostas:

14

Você pode usar find:

find . -name "*.js" -exec java -jar compiler.jar --js {} --js_output_file new{} \;
Anthon
fonte
Obrigado, e eu provavelmente pode aproveitar isso para renomear tudo porque a JS arquivos originais precisa ser substituído
Mataniko
Caso o arquivo --js e --js_output_file precisem diferir, eu criaria um script de duas linhas que tomará o nome do arquivo como parâmetro, gravaria a saída no arquivo temporário e mvo arquivo no nome original.
Anthon
Se você deseja evitar a criação de um script separado find -name '*.js' | while read jsfile; do java -jar compiler.jar --js "$jsfile" --js_output_file "new$jsfile" && mv "new$jsfile" "$jsfile"; done, faça o truque.
David Baggerman
find -execé ótimo para comandos simples. para os complexos find | xargsé muito melhor e também permite executar comandos em paralelo.
apressar
@ush talvez explique por que xargsé melhor?
Mel Boyce
7

Você também pode usar um forloop simples , especialmente se os arquivos estiverem em um único diretório (sem subdiretórios). Também pode ser modificado para funcionar com subdiretórios.

Sem recursão:

for filename in ./*.js
do
    java -jar compiler.jar --js "${filename}" --js_output_file "new${filename}"
done

ou como uma linha única equivalente:

for filename in ./*.js; do java -jar compiler.jar --js "${filename}" --js_output_file "new${filename}"; done

Para recursão em subdiretórios (requer GNU bash 4.0 ou mais recente) (obrigado @ChrisDown ):

shopt -s globstar
for filename in ./**/*.js; do
    java -jar compiler.jar --js "${filename}" --js_output_file "new${filename}"
done
um CVn
fonte
1
Isso não recursa subdiretórios, conforme solicitado na pergunta. Com o bash4 +, você pode globstarfazer isso.
Chris Baixo
1
Sim, é uma boa resposta e é bom saber, mas a outra resposta faz exatamente o que eu preciso.
Mataniko
1
Ohh, eu consegui perder completamente a parte "várias subpastas". Desculpa. Deixando a resposta por completo, no entanto.
a CVn 27/06
3
@rush Desde **pode corresponder a um nível arbitrário de recursão, **/*.jsfunciona: sprunge.us/PXQK
Chris Baixo
1
Geralmente, é uma boa ideia usar for f in ./*.js; doou for f in ./**/*.js; dopara se proteger dos nomes de arquivos que começam com a -(não sei se isso é necessário nesse caso, mas é um bom hábito).
evilsoup