2012-05-09 2 views
163

Может кто-нибудь, пожалуйста, предоставьте код, чтобы сделать следующее: Предположим, что есть каталог файлов, все из которых необходимо запускать через программу. Программа выводит результаты на стандарт. Мне нужен сценарий, который войдет в каталог, выполнит команду для каждого файла и конкатет вывод в один большой выходной файл.Сценарий Bash для выполнения команды для всех файлов в каталоге

Например, чтобы выполнить команду на 1 файл:

$ cmd [option] [filename] > results.out 
+3

Я хотел бы добавить к этому вопросу. Можно ли это сделать с помощью xargs? например, 'ls | xargs cmd [options] {filenames добавляются сюда автоматически с помощью xargs} [more arguments]> results.out' –

+0

Это может быть, но вы, вероятно, [не хотите использовать 'ls'] (http: //mywiki.wooledge. org/ParsingLs) для управления «xargs». Если 'cmd' написано грамотно, возможно, вы просто можете сделать' cmd '. – tripleee

ответ

244

Следующий код Баш передаст $ файл команды, где $ файл будет представлять каждый файл в/реж

for file in /dir/* 
do 
    cmd [option] "$file" >> results.out 
done 

Пример

[email protected] ~/foo $ touch foo.txt bar.txt baz.txt 
[email protected] ~/foo $ for i in *.txt; do echo "hello $i"; done 
hello bar.txt 
hello baz.txt 
hello foo.txt 
+13

Если в'/dir/'файлов не существует, цикл все равно выполняется один раз со значением '*' для' $ file', что может быть нежелательным. Чтобы этого избежать, включите nullglob в течение всего цикла. Добавьте эту строку перед циклом 'shopt -s nullglob' и эту строку после цикла' shopt -u nullglob #revert nullglob обратно в нормальное состояние по умолчанию'. –

+29

+1, и это просто обошлось мне обойной коллекцией обоев. все после меня, используйте двойные кавычки. «$ file» – Behrooz

+0

Если выходной файл является одним и тем же внутри цикла, гораздо более эффективно перенаправлять за пределы цикла 'done> results.out' (и, вероятно, вы можете перезаписать вместо append, как я предполагал здесь). – tripleee

112

Как об этом:

find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out 
  • -maxdepth 1 аргумент предотвращает найти из рекурсивно спускаться в подкаталоги. (Если вы хотите, чтобы такие вложенные каталоги обрабатывались, вы можете опустить это.)
  • -type -f указывает, что будут обрабатываться только простые файлы.
  • -exec cmd option {} говорит ему работать cmd с указанным option для каждого найденного файла с именем файла заменяющего {}
  • \; обозначает конец команды.
  • Наконец, выход из всех отдельных cmd казням перенаправляется results.out

Однако, если вы заботитесь о том порядке, в котором обрабатываются файлы, вы могли бы быть лучше писать цикл. Я думаю, find обрабатывает файлы в порядке inode (хотя я мог ошибаться в этом), возможно, это не то, что вы хотите.

+1

Это правильный способ обработки файлов. Использование цикла for является подверженным ошибкам по многим причинам. Также сортировка может быть выполнена с помощью других команд, таких как 'stat' и' sort', которые зависят от критериев сортировки. – tuxdna

+0

если я хотел запустить две команды, как бы связать их после опции '-exec'? Нужно ли их обертывать в одинарные кавычки или что-то еще? – frei

+0

'find' всегда лучший вариант, потому что вы можете фильтровать по шаблону имени файла с помощью опции' -name', и вы можете сделать это в одной команде. –

2

на основе подхода @Jim Льюиса:

Вот быстрое решение, использующее 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

22

я делаю это на моем Raspberry Pi из командной строки, запустив:

for i in *;do omxplayer "$i";done 
1

Мне нужно скопировать все файлы .md из одного каталога в другой, так вот что я сделал.

for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done

Что довольно трудно читать, так что позволяет разбить его.

первого CD в каталог с файлами,

for i in **/*.md; для каждого файла в шаблоне

mkdir -p ../docs/"$i" сделать этот каталог в папке DOCS за пределами папки, содержащие файлы. Что создает дополнительную папку с тем же именем, что и этот файл.

rm -r ../docs/"$i" удалить лишнюю папку, которая создается в результате mkdir -p

cp "$i" "../docs/$i" Скопируйте фактический файл

echo "$i -> ../docs/$i" Echo, что вы сделали

; done жить счастливо

1

Один быстрый и грязный способ, который иногда выполняет свою работу:

Например, чтобы найти количество строк во всех файлах текущего каталога, вы можете сделать:

find . | xargs wc -l 
Смежные вопросы