我正在编写一个 bash 脚本来对包含许多(100,000+)子目录的目录进行一些工作。对于可以传递给 for 循环的参数数量是否存在预定义限制,如下所示?
for dir in $(find . -type d)
do
# My code
done
我担心如果 find 命令返回太多目录,脚本会失败。
答案1
不要解析 find 输出,而只使用 shell 通配符 - 它更安全并且内置于 shell 中。 Shell 内置函数(如for
外部进程)不受与外部进程相同的参数列表长度限制的约束,因为不进行任何调用exec*
。
for dir in ./*/; do
# ...
done
答案2
如果你有bash 4
,你可以做一些递归的事情,比如:
shopt -s globstar
for dir in **/; do echo "$dir"; done
答案3
我不同意你接受的答案——你将要$(find)
如果您使用,即使没有礼物,也会遇到内存问题exec
。
相反,将其写为
find . -type d | while IFS= read -r dir
do
# My code
done
(注意:这假设不存在包含换行符的目录名。)
然后,您将不需要find
像命令替换那样使用临时内存来存储输出。如果该命令find
或其他命令从未终止,这也将起作用,例如:
# will not work!
for line in $(yes) ; do echo "$line" ; done
# works
yes | while IFS= read -r line ; do echo "$line" ; done
答案4
不要使用命令替换生成文件名:如果文件名包含空格或\[?*
.
对于 bash ≥4、ksh93 或 zsh,您可以通过使用glob 匹配任何深度的子目录来避免大多数find
仅使用-type d
或谓词的使用。在 bash 中,首先运行。在ksh中,先运行。-name …
**
shopt -s globstar
set -o globstar
for dir in **/; do …; done
可移植,或者在您需要更多的情况下,请使用find … -exec … +
或find … -print0 | xargs -0 …
。这种方法的另一个好处是find
与文件上的操作有点并行运行,尽管这只适用于巨大的目录树(至少数千个匹配文件)。如果您需要执行的操作不只是运行一个命令,您可以创建find
或运行 shell。xargs
find -type d -exec sh -c 'for x in "$@"; do echo "$x"; done' _ {} +
(这_
是$0
在 shell 片段中,我们不使用它。)