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 найдете другой способ.