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
代替,在运行命令之前CD进入每个文件的目录-exec
,并且可以使用-ok
代替-exec
(或-okdir
代替-execdir
)进行交互(在为每个文件运行命令之前提示)。
*:从技术上讲,find
和xargs
(默认情况下)都将使用在命令行上可以容纳的尽可能多的参数来运行命令,并且该命令要遍历所有文件所需的次数也要多次。在实践中,除非您拥有大量文件,否则没有关系,并且如果您超出了文件长度,但都需要它们在同一命令行上,则SOL会找到不同的方式。