¿Cómo ejecuto un comando en varios archivos?

13

Esto es bastante básico, tengo una carpeta con varias subcarpetas de archivos JS y quiero ejecutar el compilador Clojure de Google en todos los archivos de esas carpetas. El comando para procesar un solo archivo es el siguiente:

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

¿Cómo modifico esto para que se ejecute en cada archivo JS en la estructura de mi directorio?

Mataniko
fuente

Respuestas:

14

Puedes usar find:

find . -name "*.js" -exec java -jar compiler.jar --js {} --js_output_file new{} \;
Anthon
fuente
Gracias, y probablemente pueda aprovechar esto para cambiar el nombre de todo porque los archivos JS originales deben sobrescribirse
Mataniko
En caso de que el archivo --js y --js_output_file necesite diferir, crearía un script de dos líneas que tomara el nombre del archivo como parámetro, escribiría la salida en el archivo temporal y mvel archivo con el nombre original.
Anthon
Si quieres evitar crear un script por separado, find -name '*.js' | while read jsfile; do java -jar compiler.jar --js "$jsfile" --js_output_file "new$jsfile" && mv "new$jsfile" "$jsfile"; donedebes hacer el truco.
David Baggerman
find -execes ideal para comandos simples para los complejos find | xargses mucho mejor y también permite ejecutar comandos en paralelo.
precipitarse
@rush quizás explique por qué xargses mejor?
Mel Boyce
7

También puede usar un forbucle simple , especialmente si los archivos están dentro de un solo directorio (sin subdirectorios). También se puede modificar para trabajar con subdirectorios.

Sin recursividad:

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

o como un one-liner equivalente:

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

Para recurrir a subdirectorios (requiere GNU bash 4.0 o más reciente) (gracias @ChrisDown ):

shopt -s globstar
for filename in ./**/*.js; do
    java -jar compiler.jar --js "${filename}" --js_output_file "new${filename}"
done
un CVn
fuente
1
Esto no recurre subdirectorios como se preguntó en la pregunta. Con bash4 +, puede usar globstarpara hacerlo.
Chris Down
1
Sí, es una buena respuesta y es genial saberlo, pero la otra respuesta hace exactamente lo que necesito.
Mataniko
1
Ohh, me las arreglé para perder completamente la parte de "varias subcarpetas". Lo siento. Sin embargo, dejar la respuesta por completo.
un CVn
3
@rush Dado que **puede coincidir con un nivel arbitrario de recursión, **/*.jsfunciona: sprunge.us/PXQK
Chris Down
1
En general, es una buena idea usar for f in ./*.js; doo for f in ./**/*.js; dopara protegerse de los nombres de archivo que comienzan con un -(no sé si eso es necesario en este caso, pero de todos modos es un buen hábito).
evilsoup