Як запустити команду на кількох файлах


13

Це досить просто, у мене є папка з декількома папками файлів JS, і я хочу запустити компілятор Clojure від Google для всіх файлів у цих папках. Команда для обробки одного файлу така:

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

Як я можу змінити це для запуску кожного файлу JS в структурі мого каталогу?

Відповіді:


14

Ви можете використовувати find:

find . -name "*.js" -exec java -jar compiler.jar --js {} --js_output_file new{} \;

Дякую, і, напевно, я можу скористатися цим, щоб перейменувати все, тому що оригінальні файли JS потрібно перезаписати
Mataniko

У випадку, якщо --js та --js_output_file потрібно відрізнятись, я зробив би дворядковий скрипт, який приймає ім'я файлу як параметр, запишіть вихід у тимчасовий файл, а mvфайл - на оригінальне ім'я.
Антон

Якщо ви хочете уникнути створення окремого сценарію, find -name '*.js' | while read jsfile; do java -jar compiler.jar --js "$jsfile" --js_output_file "new$jsfile" && mv "new$jsfile" "$jsfile"; doneслід зробити фокус.
Девід Баггерман

find -execчудово підходить для простих команд. для складних - find | xargsце набагато краще, а також це дозволяє запускати команди паралельно.
пік

@rush, можливо, поясніть, чому xargsкраще?
Мел Бойс

7

Ви також можете використовувати простий forцикл, особливо якщо файли знаходяться в одній директорії (немає підкаталогів). Він може бути модифікований і для роботи з підкаталогами.

Без рекурсії:

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

або як еквівалентний однопластовий:

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

Для повторного запису в підкаталоги (потрібно GNU bash 4.0 або новіших версій ) (спасибі @ChrisDown ):

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

1
Це не повторює підкаталоги, як задано в питанні. З bash4 + ви можете globstarце зробити.
Кріс Даун

1
Так, це гарна відповідь і чудово знати, але інша відповідь робить саме те, що мені потрібно.
Матаніко

1
О, мені вдалося повністю пропустити частину "декількох папок". Вибачте. Залишаючи відповідь навколо для повноти, хоча.
CVn

3
@rush Оскільки **може відповідати довільному рівню рекурсії, **/*.jsпрацює: sprunge.us/PXQK
Chris Down

1
Як правило, це гарна ідея використовувати for f in ./*.js; doабо for f in ./**/*.js; doдля того, щоб захистити себе від назви файлів, починаючи з -(я не знаю, чи потрібно в цьому випадку, але все-таки це корисна звичка).
злий
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.