TL; DR: Если вы просто здесь для наиболее правильного ответа, вы, вероятно, хотите, чтобы мои личные предпочтения find . -name '*.txt' -exec process {} \;
(см. В нижней части этого поста). Если у вас есть время, прочитайте остальные, чтобы увидеть несколько разных способов и проблем с большинством из них.
Полный ответ:
Лучший способ зависит от того, что вы хотите сделать, но вот несколько вариантов. Пока ни один файл или папка в поддереве не имеет пробела в имени, вы можете просто зацикливать файлы:
for i in $x; do # Not recommended, will break on whitespace
process "$i"
done
Маргинально лучше вырежьте временную переменную x
:
for i in $(find -name \*.txt); do # Not recommended, will break on whitespace
process "$i"
done
Это гораздо лучше Glob , когда вы можете. Безопасный пробел, для файлов в текущем каталоге:
for i in *.txt; do # Whitespace-safe but not recursive.
process "$i"
done
Включив эту globstar
опцию, вы можете поместить все подходящие файлы в этот каталог и все его подкаталоги:
# Make sure globstar is enabled
shopt -s globstar
for i in **/*.txt; do # Whitespace-safe and recursive
process "$i"
done
В некоторых случаях, например, если имена файлов уже есть в файле, вам может потребоваться использовать read
:
# IFS= makes sure it doesn't trim leading and trailing whitespace
# -r prevents interpretation of \ escapes.
while IFS= read -r line; do # Whitespace-safe EXCEPT newlines
process "$line"
done < filename
read
можно безопасно использовать в сочетании с find
установкой соответствующего разделителя:
find . -name '*.txt' -print0 |
while IFS= read -r -d '' line; do
process "$line"
done
Для более сложных поисков вы, вероятно, захотите использовать find
, либо с его -exec
опцией, либо с -print0 | xargs -0
:
# execute `process` once for each file
find . -name \*.txt -exec process {} \;
# execute `process` once with all the files as arguments*:
find . -name \*.txt -exec process {} +
# using xargs*
find . -name \*.txt -print0 | xargs -0 process
# using xargs with arguments after each filename (implies one run per filename)
find . -name \*.txt -print0 | xargs -0 -I{} process {} argument
find
может также перейти в каталог каждого файла перед запуском команды с помощью -execdir
вместо -exec
, и может быть сделан интерактивным (запрос перед запуском команды для каждого файла) с использованием -ok
вместо -exec
(или -okdir
вместо -execdir
).
*: Технически оба find
и xargs
(по умолчанию) будут запускать команду с таким количеством аргументов, сколько они могут уместиться в командной строке, столько раз, сколько требуется, чтобы пройти через все файлы. На практике, если у вас нет очень большого количества файлов, это не будет иметь значения, и если вы превысите длину, но нуждаетесь в них в одной командной строке, вы SOL найдете другой способ.