Bash 脚本 for 循环查找和许多目录

Bash 脚本 for 循环查找和许多目录

我正在编写一个 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 globstarset -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 片段中,我们不使用它。)

相关内容