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
すべての名前を1つの検索に組み合わせる方が効率的です。コマンドラインでのシステムの長さの制限に対してパターンの数が多すぎない場合は、すべての名前を-o
で結合し、1回の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}}}
'
もう1つのアプローチはFile::Find
、Perlおよびを使用することです。これにより、ディレクトリ内のすべてのファイルに対して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
。