ファイルリストがあり、そのファイルが私のファイルシステムにあることを確認したいと思います。find
次の方法を使用してこれを実行したいと思います。
for f in $(cat file_list); do
find . -name $f > /dev/null || print $f
done
(を使用して)がファイルが見つからないか見つからないか終了するzsh
ため、機能しません。他のテストで出力が生成されているかどうかをテストできると思います(粗いですが効果的な方法はで置き換えることです)。しかし、これはトロールを使ってヤギを捕まえるのと同じ感じです(他の国では大きなハンマーとクルミの問題について話すことができます)。find
0
find
> /dev/null
|grep ''
find
有用な終了値を強制的に適用する方法はありますか?または、少なくともそのファイルのリストを入手してください。いいえ確立されたか。 (どんな賢い論理的な接続の単語を選択すると、後者がより簡単になる可能性があると想像できますが、それを理解しようとすると常に詰まっているようです)。
背景/同期:「マスター」バックアップがあり、それを削除する前に(少しのスペースを作成するために)、ローカルシステム上の特定のファイルがマスターバックアップにあることを確認したいと思います。そのため、ファイルのリストを作成しssh
てホストに編集し、見つからないファイルを見つけるための最良の方法が何であるかを考えました。
答え1
これを使用して、stat
ファイルシステムにファイルが存在するかどうかを確認できます。
組み込みのものを使用する必要があります。シェル機能ファイルが存在するかどうかをテストします。
while read f; do
test -f "$f" || echo $f
done < file_list
「テスト」はオプションで、スクリプトは実際にはそれなしで動作しますが、読みやすくするためにそのままにしています。
編集する:パスなしでファイル名のリストを処理するしかない場合は、findを使用してファイルのリストを一度作成してから、grepを使用して繰り返し、その中にどのファイルがあるかを調べることをお勧めします。
find -type f /dst > $TMPFILE
while read f; do
grep -q "/$f$" $TIMPFILE || echo $f
done < file_list
気づく:
- ファイルリストには、ディレクトリではなくファイルのみが含まれます。
- grep 一致パターンのスラッシュは、部分ファイル名ではなく完全なファイル名を比較するためのものです。
- 検索パターンの最後の「$」は行末を一致させるために使用されるため、ディレクトリ一致は取得できず、完全なファイル名パッチのみを取得できます。
答え2
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では、単純な名前を一致させるために外部コマンドは必要ありません。 .thumpバージョンを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
それとも、パターンに一致するファイルが存在するかどうかをテストするより短いですが、難解な方法ですか?N
一致するものがない場合、glob修飾子は出力を空にし、[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
呼び出し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)
答え3
最初の簡単なアプローチは次のとおりです。
a) ファイルのリストをソートします。
sort file.lst > sorted.lst
for f in $(< sortd.lst) ; do find -name $f -printf "%f\n"; done > found.lst
diff sorted.lst found.lst
行方不明者を探す
comm sorted.lst found.lst
一致するものを探す
- 罠:
- ファイル名の改行は扱いにくいです。
- ファイル名のスペースや同様の内容も悪いです。ただし、ファイルリスト内のファイルを制御できるため、このソリューションでも十分ですが...
欠点:
- find がファイルを見つけたら、別のファイルを探し続け、別のファイルを探します。追加の検索をスキップできれば良いと思います。
findは一度に複数のファイルを検索でき、いくつかの準備が必要です。
検索 -name a.file -または-name -b.file -または-name c.file ...
オプションを見つけることができますか?繰り返しますが、あらかじめソートされたファイルのリストを想定すると、次のようになります。
for f in $(< sorted.tmp) ; do locate --regexp "/"$f"$" > /dev/null || echo missing $f ; done
foo.barを検索すると、foo.baファイルまたはoo.barファイルが--regexp-constructと一致しません(pのない正規表現と混同しないでください)。
検索する特定のデータベースを指定でき、最新の結果が必要な場合は、検索する前に更新する必要があります。
答え4
FIND_EXP=". -type f \( "
while read f; do
FIND_EXP="${FIND_EXP} -iname $f -or"
done < file_list
FIND_EXP="${var%-or}"
FIND_EXP="${FIND_EXP} \)"
find ${FIND_EXP}
おそらく?