find -print0 递归

find -print0 递归

我需要列出目录及其子目录中的所有文件,将它们保存在数组中并执行一些操作(基本上是 for 循环数组并设置属性)

我开始于:

var=$(find ./ -type f)

我的问题是文件名包含空格和其他不友好的字符(不是我的错!),这使得解析字符串数组(即 find 命令的输出)变得非常复杂。

所以我发现我可以使用查找-print0它工作得很好,除了它看起来不是递归的(只有目录,而不是子目录)。

是否有一个我可以传递的参数来递归地查看或等效的命令

  • 列出目录和子目录中的所有文件
  • 将列表保存为字符串数组?

答案1

find总是递归的,但是你的:

var=$(find ./ -type f)

是一个标量变量赋值,而不是数组变量赋值。$var最终包含一个字符串:find包含换行符的完整输出²

bash 中复制 zsh 语法的数组变量赋值如下:

var=( 'first element' second-element etc... )

要获取每个文件作为 的输出find -print0,您需要拆分findNUL 字符的输出。在 zsh 中,您可以使用0参数扩展标志:

var=( ${(0)"$(find . -type f -print0)"} )

Bash 没有等效项,并且通常不能在其数据结构中存储 NUL。但是,从 4.4 版本开始,您可以将其readarray内置函数与进程替换结合使用:

readarray -td '' var < <(find . -type f -print0)

readarrayfind将输入中的每个记录(此处是通过进程替换创建的管道)存储为单独的元素。使用 时-d '',记录分隔符是 NUL 而不是换行符。使用 时-t,记录分隔符将被删除。当前版本的 bash 中不需要它,因为 bash 无论如何都无法在其变量中存储 NUL,但我们添加它是为了面向未来。

要循环元素,你可以这样做:

for file in "${var[@]}"; do
  something with "$file"
done

在这里,您也可以不使用数组并直接在findwith 的输出上循环:

while IFS= read -rd '' -u3 file; do
  something with "$file"
done 3< <(find . -type f -print0)

也可以看看为什么循环查找的输出是不好的做法?find了解如何正确循环通常找到的文件。


-prune¹ 除非你明确告诉它不要使用或进入某些目录-xdev,或者使用某些find实现限制深度-maxdepth。但是,除非您使用-L选项或-follow谓词4,否则它不会遵循目录的符号链接

² 除了被命令替换删除的尾随部分。

³ 好吧,在 中,您首先zsh不需要find非标准的,您只需使用其递归 glob 和 glob 限定符:或遵循符号链接。-print0var=( **/*(ND.) )var=( ***/*(ND.) )

4但请注意,-L/-follow也会对行为产生影响-type。这里-type f最终还会选择常规文件的符号链接。通过 GNU 实现find,您可以使用-xtype fwith-L仅选择常规文件,而不是像-type fwithout 那样符号链接到常规文件-L

答案2

我犯了一个错误,我使用的是软链接,而我没有使用寻找-L旗帜。

original_list=()
while IFS= read -r -d $'\0'; do
    original_list+=("$REPLY")
done < <(find -L ./ -type f -print0)

这有效!

相关内容