Как запустить команду для нескольких файлов

13

Это довольно просто, у меня есть папка с несколькими подпапками файлов JS, и я хочу запустить компилятор Google Clojure для всех файлов в этих папках. Команда для обработки одного файла выглядит следующим образом:

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

Как я могу изменить это для запуска на каждом файле JS в моей структуре каталогов?

Mataniko
источник

Ответы:

14

Вы можете использовать find:

find . -name "*.js" -exec java -jar compiler.jar --js {} --js_output_file new{} \;
Энтон
источник
Спасибо, и я, вероятно, могу использовать это, чтобы переименовать все, потому что оригинальные файлы JS должны быть перезаписаны
Mataniko
В случае, если --js и --js_output_file должны различаться, я бы сделал двухстрочный скрипт, который принимает имя файла в качестве параметра, записывал вывод во временный файл, а mvфайл - в исходное имя.
Anthon
Если вы хотите избежать создания отдельного скрипта, 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гораздо лучше, а также позволяет выполнять команды параллельно.
Раш
@ Может быть, объяснить, почему 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
CVn
источник
1
Это не возвращает подкаталоги, как указано в вопросе. С bash4 +, вы можете использовать globstarдля этого.
Крис Даун
1
Да, это хороший ответ и приятно знать, но другой ответ делает именно то, что мне нужно.
Матанико
1
Ох, мне удалось полностью пропустить часть "несколько подпапок". Сожалею. Однако для полноты изложения оставим ответ.
CVn
3
@rush Так как **может соответствовать произвольному уровню рекурсии, **/*.jsработает: sprunge.us/PXQK
Крис Даун
1
Как правило, это хорошая идея, чтобы использовать for f in ./*.js; doили for f in ./**/*.js; doдля того, чтобы защитить себя от имен файлов, начинающихся с -(я не знаю, если это необходимо в этом случае, но это хорошая привычка в любом случае).
evilsoup