可以通过以下方式轻松地递归迭代目录中的文件:
find . -type f -exec bar {} \;
然而,上面的方法不适用于更复杂的事情,因为需要完成很多条件分支、循环等。我曾经在上面使用过这个:
while read line; do [...]; done < <(find . -type f)
但是,这似乎不适用于包含模糊字符的文件:
$ touch $'a\nb'
$ find . -type f
./a?b
有没有其他方法可以很好地处理这些晦涩的字符?
答案1
还有一个用途安全的find
:
while IFS= read -r -d '' -u 9
do
[Do something with "$REPLY"]
done 9< <( find . -type f -exec printf '%s\0' {} + )
(这适用于任何 POSIX find
,但 shell 部分需要 bash。使用 *BSD 和 GNU find ,您可以使用-print0
代替-exec printf '%s\0' {} +
,它会稍微快一些。)
这使得在循环内使用标准输入成为可能,并且它可以与任何小路。
答案2
这样做很简单:
find -exec sh -c 'inline script "$0"' {} \;
或者...
find -exec executable_script {} \;
答案3
最简单(但安全)的方法是使用 shell 通配符:
$ for f in *; do printf ":%s:\n" "$f"; done
:a b:
:c
d:
:-e:
:e f:
h:
要使上述递归到子目录(在 bash 中),您可以使用该globstar
选项;还设置dotglob
为匹配名称以以下开头的文件.
:
$ shopt -s globstar dotglob
$ for f in **/*; do printf ":%s:\n" "$f"; done
:a b:
:c
d:
:-e:
:e f:
:foo:
:foo/file1:
:foo/file two:
h:
请注意,直到 bash 4.2,**/
递归到目录的符号链接。从 bash 4.3 开始,**/
仅递归到目录,例如find
.
另一个常见的解决方案是使用find -print0
with xargs -0
:
$ touch -- 'a b' $'c\nd' $'e\tf' $'g\rh' '-e'
$ find . -type f -print0 | xargs -0 -I{} printf ":%s:\n" {}
h:/g
:./e f:
:./a b:
:./-e:
:./c
d:
请注意,h:/g
实际上是正确的,因为文件名包含\r
.
答案4
可移植地执行读取循环有点困难,但特别是对于 bash,您可以尝试类似的方法这。
相关部分:
while IFS= read -d $'\0' -r file ; do
printf 'File found: %s\n' "$file"
done < <(find . -iname 'foo*' -print0)
它指示find
打印由 NUL 字符 (0x00) 分隔的输出,并read
获取 NUL 分隔的行 ( -d $'\0'
),而不将反斜杠处理为其他字符的转义 ( -r
),并且不对行进行任何分词 ( IFS=
)。由于 0x00 是一个不能出现在 Unix 中的文件名或路径中的字节,因此这应该可以处理所有奇怪的文件名问题。