Comment exécuter une commande sur plusieurs fichiers

13

C'est assez basique, j'ai un dossier avec plusieurs sous-dossiers de fichiers JS et je veux exécuter le compilateur Clojure de Google sur tous les fichiers de ces dossiers. La commande pour traiter un seul fichier est la suivante:

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

Comment puis-je modifier cela pour qu'il s'exécute sur chaque fichier JS de ma structure de répertoires?

Mataniko
la source

Réponses:

14

Vous pouvez utiliser find:

find . -name "*.js" -exec java -jar compiler.jar --js {} --js_output_file new{} \;
Anthon
la source
Merci, et je peux probablement en tirer parti pour tout renommer car les fichiers JS d'origine doivent être écrasés
Mataniko
Dans le cas où --js et --js_output_file doivent différer, je ferais un script à deux lignes qui prend le nom de fichier comme paramètre, écrire la sortie dans un fichier temporaire et mvle fichier dans le nom d'origine.
Anthon
Si vous voulez éviter de créer un script séparé, find -name '*.js' | while read jsfile; do java -jar compiler.jar --js "$jsfile" --js_output_file "new$jsfile" && mv "new$jsfile" "$jsfile"; donefaites l'affaire.
David Baggerman
find -execest idéal pour les commandes simples. pour les plus complexes, find | xargsc'est beaucoup mieux et cela permet également d'exécuter des commandes en parallèle.
rush
@rush explique peut-être pourquoi xargsc'est mieux?
Mel Boyce
7

Vous pouvez également utiliser une forboucle simple , surtout si les fichiers se trouvent dans un seul répertoire (pas de sous-répertoires). Il peut également être modifié pour fonctionner avec des sous-répertoires.

Sans récursivité:

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

ou comme doublure équivalente:

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

Pour recurse dans des sous-répertoires (nécessite GNU bash 4.0 ou plus récent) (merci @ChrisDown ):

shopt -s globstar
for filename in ./**/*.js; do
    java -jar compiler.jar --js "${filename}" --js_output_file "new${filename}"
done
un CVn
la source
1
Cela ne recrée pas les sous-répertoires comme demandé dans la question. Avec bash4 +, vous pouvez le globstarfaire.
Chris Down
1
Oui, c'est une bonne réponse et super à savoir, mais l'autre réponse fait exactement ce dont j'ai besoin.
Mataniko
1
Ohh, j'ai réussi à manquer complètement la partie "plusieurs sous-dossiers". Désolé. Laissant la réponse dans un souci d'exhaustivité, cependant.
un CVn le
3
@rush Puisque **peut correspondre à un niveau arbitraire de récursivité, **/*.jsfonctionne: sprunge.us/PXQK
Chris Down
1
C'est généralement une bonne idée d'utiliser for f in ./*.js; doou for f in ./**/*.js; doafin de vous protéger des noms de fichiers commençant par un -(je ne sais pas si c'est nécessaire dans ce cas, mais c'est quand même une bonne habitude).
evilsoup