![find -print0 递归](https://linux22.com/image/215298/find%20-print0%20%E9%80%92%E5%BD%92.png)
我需要列出目录及其子目录中的所有文件,将它们保存在数组中并执行一些操作(基本上是 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
,您需要拆分find
NUL 字符的输出。在 zsh 中,您可以使用0
参数扩展标志:
var=( ${(0)"$(find . -type f -print0)"} )
Bash 没有等效项,并且通常不能在其数据结构中存储 NUL。但是,从 4.4 版本开始,您可以将其readarray
内置函数与进程替换结合使用:
readarray -td '' var < <(find . -type f -print0)
readarray
find
将输入中的每个记录(此处是通过进程替换创建的管道)存储为单独的元素。使用 时-d ''
,记录分隔符是 NUL 而不是换行符。使用 时-t
,记录分隔符将被删除。当前版本的 bash 中不需要它,因为 bash 无论如何都无法在其变量中存储 NUL,但我们添加它是为了面向未来。
要循环元素,你可以这样做:
for file in "${var[@]}"; do
something with "$file"
done
在这里,您也可以不使用数组并直接在find
with 的输出上循环:
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 限定符:或遵循符号链接。-print0
var=( **/*(ND.) )
var=( ***/*(ND.) )
4但请注意,-L
/-follow
也会对行为产生影响-type
。这里-type f
最终还会选择常规文件的符号链接。通过 GNU 实现find
,您可以使用-xtype f
with-L
仅选择常规文件,而不是像-type f
without 那样符号链接到常规文件-L
答案2
我犯了一个错误,我使用的是软链接,而我没有使用寻找和-L旗帜。
original_list=()
while IFS= read -r -d $'\0'; do
original_list+=("$REPLY")
done < <(find -L ./ -type f -print0)
这有效!