Перебирать определенные файлы в каталоге, используя Bash find
Shellcheck не любит мой for
над find
петля в баш.
for f in $(find $src -maxdepth 1 -name '*.md'); do wc -w < "$f" >> $path/tmp.txt; done
Вместо этого предлагается:
1 while IFS= read -r -d '' file
2 do
3 let count++
4 echo "Playing file no. $count"
5 play "$file"
6 done < <(find mydir -mtime -7 -name '*.mp3' -print0)
7 echo "Played $count files"
Я понимаю большинство из них, но некоторые вещи до сих пор неясны.
В первой строке: что такое '' file
?
В шестой строке: что делает пустое пространство в < < (find).
Являются ли <
перенаправляет, как обычно? Если они есть, что значит перенаправить в do
блок?
Может кто-нибудь помочь разобрать это? Это правильный способ перебирать файлы определенного вида в каталоге?
2 ответа
В первой строке: что такое файл?
В соответствии с help read
, тот ''
это аргумент -d
параметр:
-d delim continue until the first character of
DELIM is read, rather than newline
В шестой строке: что делает пустое пространство в <<(find).
Там есть два отдельных оператора. Есть <
стандартный оператор перенаправления ввода / вывода, за которым следует <(...)
конструкция, которая является специфической для bash конструкцией, которая выполняет подстановку процесса:
Process Substitution
Process substitution is supported on systems that
support named pipes (FIFOs) or the /dev/fd method of naming
open files. It takes the form of <(list) or >(list). The
process list is run with its input or output connected
to a FIFO or some file in /dev/fd...
Так что это отправка вывода find
командовать в do
петля.
<Перенаправления, как обычно? Если они есть, что значит перенаправить в блок do?
Перенаправление в цикл означает, что любая команда внутри этого цикла, которая читает из stdin
будет читать из перенаправленного источника ввода. Как побочный эффект, все внутри этого цикла выполняется в подоболочке, что имеет значение в отношении области видимости переменных: переменные, установленные внутри цикла, не будут видны вне цикла.
Может кто-нибудь помочь разобрать это? Это правильный способ перебирать файлы определенного вида в каталоге?
Для записи, я бы обычно делал это по трубам find
в xargs
, хотя, какое решение лучше, зависит в определенной степени от того, что вы пытаетесь сделать. Два примера в вашем вопросе делают совершенно разные вещи, и не ясно, чего вы на самом деле пытаетесь достичь.
Но например:
find $src -maxdepth 1 -name '*.md' -print0 |
xargs -0 -iDOC wc -w DOC
Это будет работать wc
на всех *.md
файлы. -print0
в find
(и -0
в xargs
) разрешить этой команде правильно обрабатывать имена файлов со встроенными пробелами (например, This is my file.md
). Если вы знаете, что у вас их нет, просто сделайте:
find $src -maxdepth 1 -name '*.md' |
xargs -iDOC wc -w DOC
Как правило, вам нужно использовать find
если вы хотите выполнить рекурсивный поиск по дереву каталогов (хотя в современном bash вы можете установить параметр оболочки globstar
, как предполагает Shellcheck). Но в этом случае вы указали -maxdepth 1, так что ваш find
Команда просто перечисляет файлы, которые соответствуют шаблону "$src"/*.md
, В этом случае гораздо проще и надежнее использовать глоб (шаблон):
for f in "$src"/*.md; do
wc -w < "$f"
done >> "$path"/tmp.txt
(Я также процитировал все расширения переменных для безопасности и переместил перенаправление вывода, чтобы оно применялось ко всему циклу for, что несколько более эффективно.)
Если вам нужно использовать find
(потому что шар не будет работать), тогда вы должны попытаться использовать -exec
опция для поиска, которая не требует возиться с другими опциями, чтобы избежать неправильной обработки специальных символов в именах файлов. Например, вы можете сделать это:
find "$src" -maxdepth 1 -name '*.md' -exec do wc -w {} + >> "$path"/tmp.txt
Чтобы ответить на ваши конкретные вопросы:
В
IFS= read -r -d '' file
,''
это аргумент-d
вариант. Эта опция используется для указания символа, который разделяет строки для чтения; по умолчанию используется символ перевода строки, чтобыread
читает по одной строке за раз. Пустая строка совпадает с указанием символа NUL, чтоfind
выводит в конце каждого имени файла, если указать-print0
вариант. (В отличие от-exec
,-print0
не является стандартом Posix, поэтому не гарантируется работа с каждымfind
реализация, но на практике это довольно общедоступно.)Пространство между
<
а также<(...)
чтобы избежать создания токена<<
, что указывало бы здесь на документ. Вместо этого он указывает перенаправление (<
) из процесса замены (<(...)
).