find
认为没有发现任何成功的特殊情况(没有发生错误)。测试文件是否符合某些find
条件的一般方法是测试的输出是否find
为空。为了在有匹配文件时提高效率,请-quit
在GNU find上使用它来使它在第一次匹配时退出,或者在其他系统上head
(head -c 1
如果可用,否则head -n 1
是标准的)在其他系统上退出,以使它死于管道破裂而不是产生长输出。
while IFS= read -r name; do
[ -n "$(find . -name "$name" -print | head -n 1)" ] || printf '%s\n' "$name"
done <file_list
在bash≥4或zsh中,不需要外部find
命令即可进行简单的名称匹配:可以使用**/$name
。重击版本:
shopt -s nullglob
while IFS= read -r name; do
set -- **/"$name"
[ $# -ge 1 ] || printf '%s\n' "$name"
done <file_list
Zsh版本的原理类似:
while IFS= read -r name; do
set -- **/"$name"(N)
[ $# -ge 1 ] || print -- "$name"
done <file_list
或者,这是测试与模式匹配的文件是否存在的一种更简短但更隐秘的方法。glob限定符N
将在没有匹配项的情况下使输出为空,[1]
仅保留第一个匹配项,然后e:REPLY=true:
将每个匹配项更改为扩展为1
而不是匹配的文件名。因此,**/"$name"(Ne:REPLY=true:[1]) false
将其扩展为true false
是否存在匹配项,或者扩展false
为没有匹配项。
while IFS= read -r name; do
**/"$name"(Ne:REPLY=true:[1]) false || print -- "$name"
done <file_list
将您的所有名称组合为一个搜索会更有效。如果在命令行上模式的数量对于系统的长度限制而言不是太大,则可以使用将所有名称连接在一起-o
,进行一次find
调用,然后对输出进行后处理。如果名称中都不包含外壳元字符(因此名称也包含find
模式),则可以使用awk(未经测试)进行后处理:
set -o noglob; IFS='
'
set -- $(<file_list sed -e '2,$s/^/-o\
/')
set +o noglob; unset IFS
find . \( "$@" \) -print | awk -F/ '
BEGIN {while (getline <"file_list") {found[$0]=0}}
wanted[$0]==0 {found[$0]=1}
END {for (f in found) {if (found[f]==0) {print f}}}
'
另一种方法是使用Perl和File::Find
,这使得为目录中的所有文件运行Perl代码变得容易。
perl -MFile::Find -l -e '
%missing = map {chomp; $_, 1} <STDIN>;
find(sub {delete $missing{$_}}, ".");
print foreach sort keys %missing'
另一种方法是在两边生成文件名列表并进行文本比较。Zsh版本:
comm -23 <(<file_list sort) <(print -rl -- **/*(:t) | sort)
locate
。