Может ли кто-нибудь предоставить код для выполнения следующих действий: Предположим, что существует каталог файлов, все из которых необходимо запустить через программу. Программа выводит результаты на стандартный вывод. Мне нужен скрипт, который войдет в каталог, выполнит команду для каждого файла и объединит вывод в один большой выходной файл.
Например, чтобы запустить команду для 1 файла:
$ cmd [option] [filename] > results.out
ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out
ls
для вожденияxargs
. Еслиcmd
это вообще грамотно написано, возможно, вы можете просто сделатьcmd <wildcard>
.Ответы:
Следующий код bash передаст $ file команде, где $ file будет представлять каждый файл в / dir
пример
источник
/dir/
, цикл все равно выполняется один раз со значением '*'$file
, что может быть нежелательно. Чтобы избежать этого, включите nullglob на время цикла. Добавьте эту строку перед цикломshopt -s nullglob
и эту строку после циклаshopt -u nullglob #revert nullglob back to it's normal default state
.done >results.out
(и, вероятно, тогда вы можете перезаписать вместо добавления, как я и предполагал здесь).Как насчет этого:
-maxdepth 1
Аргумент предотвращает рекурсивный поиск find в любых подкаталогах. (Если вы хотите, чтобы такие вложенные каталоги обрабатывались, вы можете пропустить это.)-type -f
указывает, что будут обрабатываться только простые файлы.-exec cmd option {}
говорит ему запускатьсяcmd
с указаннымoption
для каждого найденного файла, с заменой имени файла на{}
\;
обозначает конец команды.cmd
исполнений перенаправляются наresults.out
Однако, если вы заботитесь о порядке обработки файлов, вам лучше написать цикл. Я думаю, что
find
обрабатывает файлы в порядке inode (хотя я могу ошибаться в этом), что может не соответствовать вашим ожиданиям.источник
stat
иsort
, что, конечно, зависит от критериев сортировки.-exec
опции? Должен ли я обернуть их в одинарные кавычки или что-то?find
всегда лучший вариант, потому что вы можете фильтровать по шаблону имени файла с опцией,-name
и вы можете сделать это в одной команде.-exec
варианты:find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;
Я делаю это на моем Raspberry Pi из командной строки, выполнив:
источник
Принятые / высоко оцененные ответы великолепны, но в них отсутствуют некоторые мелкие детали. В этом посте рассматриваются случаи, как лучше справляться с неудачным раскрытием имени оболочки (glob), когда имена файлов содержат встроенные символы новой строки / тире и перемещение направления вывода команды из цикла for при записи результатов в файл.
При запуске расширения оболочки glob с использованием
*
существует возможность сбоя раскрытия, если в каталоге нет файлов, а в команду, которая будет запущена, будет передана нераскрытая строка глобуса, что может привести к нежелательным результатам.bash
Оболочка обеспечивает расширенный вариант оболочки для этого с помощьюnullglob
. Таким образом, цикл в основном выглядит следующим образом внутри каталога, содержащего ваши файлыЭто позволяет безопасно выйти из цикла for, когда выражение
./*
не возвращает никаких файлов (если каталог пуст)или совместимым образом POSIX (
nullglob
этоbash
специфический)Это позволяет вам войти в цикл, когда выражение не выполнится один раз, и
[ -f "$file" ]
проверить условие, является ли нераскрытая строка./*
допустимым именем файла в этом каталоге, чего не было бы. Таким образом, в этом случае сбой, используя,continue
мы возвращаемся кfor
циклу, который не будет выполняться в дальнейшемТакже обратите внимание на использование
--
перед передачей аргумента имени файла. Это необходимо, потому что, как отмечалось ранее, имена файлов оболочки могут содержать тире в любом месте имени файла. Некоторые из команд оболочки интерпретируют это и рассматривают их как параметр команды, когда имя не указано правильно в кавычках, и выполняют команду, думая, если указан флаг.В этом случае
--
сигнализирует об окончании параметров командной строки, что означает, что команда не должна анализировать любые строки за этой точкой как флаги команды, а только как имена файлов.Двойные кавычки имен файлов правильно решают случаи, когда имена содержат символы глобуса или пробелы. Но имена файлов * nix также могут содержать в себе новые строки. Таким образом, мы ограничиваем имена файлов единственным символом, который не может быть частью действительного имени файла - null byte (
\0
). Посколькуbash
внутренне используютсяC
строки стиля, в которых нулевые байты используются для обозначения конца строки, это правильный кандидат для этого.Таким образом, используя
printf
опцию оболочки для разделения файлов с этим нулевым байтом, используя-d
опциюread
команды, мы можем сделать нижеСимволы
nullglob
andprintf
и обернуты вокруг,(..)
что означает, что они в основном выполняются в под-оболочке (дочерняя оболочка), потому что, чтобы избежатьnullglob
возможности отразить на родительской оболочке, после завершения команды.-d ''
Вариантread
команды является не POSIX совместимым, поэтому нуждается вbash
оболочке для этого нужно сделать. С помощьюfind
команды это можно сделать какДля
find
реализаций, которые не поддерживают-print0
(кроме реализаций GNU и FreeBSD), это можно эмулировать с помощьюprintf
Другим важным исправлением является перемещение направления из цикла for, чтобы уменьшить количество файловых операций ввода-вывода. При использовании внутри цикла оболочка должна выполнять системные вызовы дважды для каждой итерации цикла for, один раз для открытия и один раз для закрытия дескриптора файла, связанного с файлом. Это станет узким местом для вашей производительности при выполнении больших итераций. Рекомендуемое предложение - переместить его за пределы цикла.
Расширяя приведенный выше код с помощью этих исправлений, вы можете сделать
который будет в основном помещать содержимое вашей команды для каждой итерации ввода вашего файла в стандартный вывод, а когда цикл завершится, откройте целевой файл один раз для записи содержимого стандартного вывода и его сохранения. Эквивалентная
find
версия того жеисточник
Один быстрый и грязный способ, который иногда выполняет свою работу:
Например, чтобы найти количество строк во всех файлах в текущем каталоге, вы можете сделать:
источник
~/.local/share/steam
. Запустил пар. Он удалил все в системе, принадлежащей пользователю». отчет об ошибке.Мне нужно было скопировать все файлы .md из одного каталога в другой, так что вот что я сделал.
for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done
Который довольно трудно читать, поэтому давайте разберем его.
сначала перейдите в каталог с вашими файлами,
for i in **/*.md;
для каждого файла в вашем шаблонеmkdir -p ../docs/"$i"
сделайте этот каталог в папке docs вне папки, содержащей ваши файлы. Который создает дополнительную папку с тем же именем, что и этот файл.rm -r ../docs/"$i"
удалить лишнюю папку, созданную в результатеmkdir -p
cp "$i" "../docs/$i"
Скопируйте фактический файлecho "$i -> ../docs/$i"
Эхо, что ты сделал; done
Жить долго и счастливоисточник
**
работыglobstar
должен быть установлен параметр оболочки:shopt -s globstar
Ты можешь использовать
xarg
ls | xargs -L 1 -d '\n' your-desired-command
-L 1
вызывает пропуск 1 предмет за раз-d '\n'
сделать вывод изls
split'ed на основе новой строки.источник
Основываясь на подходе @Jim Lewis:
Вот быстрое решение, использующее
find
и сортирующее файлы по дате их изменения:Для сортировки смотрите:
http://www.commandlinefu.com/commands/view/5720/find-files-and-list-them-sorted-by-modification-time
источник
-print0
для которогоfind
и-0
дляxargs
которого используются пустые символы вместо пробелов (включая переводы строки).-print0
- это то, что помогает, но весь конвейер должен использовать что-то вроде этого, аsort
это не такя думаю, что простое решение:
источник
Максимальная глубина
Я нашел, что это хорошо работает с ответом Джима Льюиса, просто добавьте немного так:
Порядок сортировки
Если вы хотите выполнить в порядке сортировки, измените его следующим образом:
Просто для примера, это будет выполнено в следующем порядке:
Неограниченная глубина
Если вы хотите выполнить на неограниченной глубине при определенных условиях, вы можете использовать это:
затем поместите поверх каждого файла в дочерних каталогах, как это:
и где-нибудь в теле родительского файла:
источник