Не мог бы кто-нибудь предоставить код, чтобы сделать следующее: Предположим, есть каталог файлов, каждый из которых нужно прогнать через программу. Программа выводит результаты в стандартный вывод. Мне нужен сценарий, который войдет в каталог, выполнит команду для каждого файла и объединит результаты в один большой выходной файл.
Например, чтобы выполнить команду для 1 файла:
$ cmd [option] [filename] > results.out
Следующий код bash передаст команде $file, где $file будет представлять каждый файл в /dir
for file in /dir/*
do
cmd [option] "$file" >> results.out
done
Пример
el@defiant ~/foo $ touch foo.txt bar.txt baz.txt
el@defiant ~/foo $ for i in *.txt; do echo "hello $i"; done
hello bar.txt
hello baz.txt
hello foo.txt
Как насчет этого:
find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out
-maxdepth 1
предотвращает рекурсивный спуск find в
любые вложенные каталоги. (Если вы хотите, чтобы такие вложенные каталоги обрабатывались, этот аргумент можно опустить).-type -f
указывает, что будут обрабатываться только простые файлы.-exec cmd option {}
указывает запустить cmd
с указанной option
для каждого найденного файла, при этом имя файла заменяется на {}
.\;
обозначает конец команды.cmd
перенаправляется в файл
results.out
Однако, если вам важен порядок обработки файлов, лучше написать цикл.
лучше написать цикл. Я думаю, что find
обрабатывает файлы
в порядке следования (хотя я могу ошибаться в этом), что может быть не тем, что
что может быть не тем, что вам нужно.
Мне нужно скопировать все .MD файлы из одного каталога в другой, так вот что я сделал.
`ибо я в */.МД;делаем mkdir -Р ../документов/то" Я" и &&усилителя; РМ -Р ../документов/то" Я" и &&усилителя; КП " В$Я" и " по../документов/$я" и &АМП;& Эхо " Я -> ../документов/$я и решила попробовать сделать
Что довольно трудно читать, так что давайте разбить его вниз.
первый компакт-диск в каталог с файлами,
`ибо я в */.МД; для каждого файл в свой шаблон
`команды mkdir -Р купила ../документов/&;$я" и сделать этот каталог в папке Docs вне папку, содержащую файлы. Что создает дополнительную папку с именем этого файла.
РМ -Р ../документов/то" Я"в удалить лишнюю папку, которая была создана в результате команды mkdir -Р
КП " В$Я" и " от../документов/$я"
в скопировать сам файл
Эхо " Я -> ../документов/$я"
в Эхе, что ты сделал
сделали
жить долго и счастливо
Я нашел это хорошо работает с Джим Льюис'ы ответ Просто добавьте немного как это:
$ export DIR=/path/dir && cd $DIR && chmod -R +x *
$ find . -maxdepth 1 -type f -name '*.sh' -exec {} \; > results.out
Если вы хотите выполнить сортировку, изменить ее так:
$ export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -maxdepth 2 -type f -name '*.sh' | sort | bash > results.out
Просто для примера, это будет выполняться в следующем порядке:
bash: 1: ./assets/main.sh
bash: 2: ./builder/clean.sh
bash: 3: ./builder/concept/compose.sh
bash: 4: ./builder/concept/market.sh
bash: 5: ./builder/concept/services.sh
bash: 6: ./builder/curl.sh
bash: 7: ./builder/identity.sh
bash: 8: ./concept/compose.sh
bash: 9: ./concept/market.sh
bash: 10: ./concept/services.sh
bash: 11: ./product/compose.sh
bash: 12: ./product/market.sh
bash: 13: ./product/services.sh
bash: 14: ./xferlog.sh
Если вы хотите исполнять на неограниченную глубину при определенных условиях, вы можете использовать это:
export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -type f -name '*.sh' | sort | bash > results.out
затем положите сверху каждого файлы в каталогах, как ребенок:
#!/bin/bash
[[ "$(dirname `pwd`)" == $DIR ]] && echo "Executing `realpath $0`.." || return
и где-то в теле родительского файла:
if <a condition is matched>
then
#execute child files
export DIR=`pwd`
fi
Принятых/высокого голосовал ответы замечательные, но им не хватает несколько мельчайшие детали. Это сообщение охватывает случаи о том, как лучше обрабатывать, когда корпус имени пути расширения (Глоб) в случае, когда имена файлов содержат встроенные переводы строк/символов тире и двигать команду вывода повторное направление выхода из цикла при записи результатов в файл.
При запуске оболочки Глоб расширения, используя *
есть возможность для расширения с ошибкой, если есть но файлы в каталоге и ООН расширила Глоб строка будет передан команде должен быть запущен, Что может иметь нежелательные результаты. В Баш
Shell предоставляет возможность расширенной оболочки для этого, используя nullglob
. Так что цикл в основном будет следующим образом внутри директория, содержащая файлы
shopt -s nullglob
for file in ./*; do
cmdToRun [option] -- "$file"
done
Это позволит вам благополучно выйти из цикла, если выражение ./*
возвращает любые файлы ( если каталог пуст)
или в POSIX-совместимой путь (nullglob
это Баш
конкретно)
for file in ./*; do
[ -f "$file" ] || continue
cmdToRun [option] -- "$file"
done
Это позволяет перейти внутри цикла, если выражение не раз и условие [ -ф " в файл$то" ]
проверить, если ООН-расширить строку/. *
является допустимым именем файла в этом каталоге, который бы'т быть. Так что на эту ошибку состояние, используя "продолжить" мы вернуться обратно в для
петли, которая выиграла'т впоследствии работать.
Также обратите внимание на использование --
просто перед передачей аргумента имя файла. Это необходимо потому, что, как уже отмечалось, имена оболочка может содержать дефисы в любом месте в имени файла. Некоторые команды оболочки интерпретировать, что и относиться к ним как опция команды, когда имя не правильно процитировал и выполняет команды, думая, если флаг предоставляется.
В --
сигнализирует об окончании параметров командной строки в этом случае значит, команда должна'т разобрать все строки после этой точки, как флаги команды, но только как имена.
Дважды цитируя имена файлов правильно решает случаи, когда имена содержат символы Глоб или пробелы. Но *Никс имена также могут содержать переводы строк в них. Так что мы де-лимит файлов с Единственный персонаж, который не может быть частью действительного именем - нулевой байт (\0
). Поскольку Баш
внутренне использует `строки в стиле C, в которой нулевой байт используются для обозначения конца строки, это подходящий кандидат для этого.
Таким образом, используя е
вариант оболочки для разделения файлов с этого нулевого байта, используя -д
вариант читать
команду, мы можем сделать ниже
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done
В nullglob
и Е
объять ( .. )
, который означает, что они в основном работают в суб-оболочки (оболочки ребенка), потому что, чтобы избежать nullglob
возможность отражать на материнской оболочки, после завершения команды. В-д ''в
прочитатькоманда уступчивый _не_ в POSIX, так нужно
БашShell для этого надо делать. Используя
найти команду` это может быть сделано как
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)
Для найти
реализаций, что Дон'т поддержку -print0 команды
(кроме GNU и реализации во FreeBSD), это можно эмулировать через е
find . -maxdepth 1 -type f -exec printf '%s\0' {} \; | xargs -0 cmdToRun [option] --
Еще одно важное исправление для перемещения повторное направление выхода из цикла, чтобы уменьшить большое количество файлового ввода/вывода при использовании внутри цикла, оболочка для выполнения системных вызовов, дважды на каждой итерации цикла, после открытия и после закрытия дескриптора файла, связанного с файлом. Это станет бутылка-образным вырезом на производительность для выполнения больших итераций. Рекомендованное предложение было бы переместить его вне цикла.
Расширив приведенный выше код с помощью этого исправления, вы могли бы сделать
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done > results.out
которые в основном положить содержимое вашей команды на каждой итерации вашего входного файла в stdout и когда цикл заканчивается, откройте целевой файл для записи содержимое в stdout и сохраняя его. Версия эквивалентом найти
в то же самое будет
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out
Основываясь на подходе @Jim Lewis'a:
Вот быстрое решение с использованием find
, а также сортировки файлов по дате модификации:
$ find directory/ -maxdepth 1 -type f -print0 | \
xargs -r0 stat -c "%y %n" | \
sort | cut -d' ' -f4- | \
xargs -d "\n" -I{} cmd -op1 {}
Для сортировки см:
http://www.commandlinefu.com/commands/view/5720/find-files-and-list-them-sorted-by-modification-time