私たちは、多数のファイル(500万以上)を含むSANを持っています。開発者スクリプトの奇妙なエラーのためにいくつかのファイルが削除され、今削除されたファイルを特定する必要があります。
これで、次のように確認する必要があるファイル名のリスト(データベース内)があります。
49
50
51
52
find
次のコマンドを使用して、単一のファイルと複数のファイルに対してこれを行う方法を見つけました。
find /mnt/SAN/documents/ -type f -name"92441_1"
この方法は機能しますが、このコマンドを使用して200,000を超えるファイルを確認することはできません。それで、find
私のファイルから入力を取得するコマンドを取得する方法を知っている人がいるのか、それともこのタスクを実行するために使用できる他のコマンドがあるのか疑問に思います。
答え1
私は次のようにします(GNUツールを使用していると仮定):
find /mnt/SAN/documents -type f -print0 | awk -F / '
NR == FNR{check[$0]; next}
$NF in check {print "found:", $0; delete check[$NF]}
END {
for (i in check)
print "Not found:", i
}' filename.list RS='\0' -
これはになりますfilename.list
。
またはすべての発生を報告します。
find /mnt/SAN/documents -type f -print0 | awk -F / '
NR == FNR{check[$0]; notfound[$0]; next}
$NF in check {print "found:", $0; delete notfound[$NF]}
END {
for (i in notfound)
print "Not found:", i
}' filename.list RS='\0' -
答え2
次のようなものを使用してください
find /mnt/SAN/documents/ -type f | perl -ple 's,^.*/,,' > files_currently_present
パスなしで現在のディスクにあるファイルのリストを作成し、
comm -2 -3 filelist_from database files_currently_present
これをバックアップリストと比較し、メッセージファイルリストを生成します。
答え3
最も簡単な方法は、シェルループを使用してファイルからファイル名を読み取り、バックfind
グラウンドで複数のコマンドを実行することです。
while IFS= read -r file; do
find /mnt/SAN/documents/ -type f -name "$file" &
done < fileList.txt > foundFiles.txt
ただし、これにより、200,000を超えるインスタンスが起動し、find
システムがダウンする可能性があります。より良いアプローチは、find
各ファイル名を提供する複雑なコマンドを書くことです。
$ printf 'find /mnt/SAN/documents/ -type f '; while IFS= read -r file; do printf -- '-name "%s" -o ' "$file"; done < fileList.txt | sed 's/-o $/\n/'
find /mnt/SAN/documents/ -type f -name "49" -o -name "50" -o -name "51" -o -name "52"
その後、コピー/貼り付けまたは次を使用してコマンド自体を実行できます。
eval $(printf 'find /mnt/SAN/documents/ -type f '; \
while IFS= read -r file; do
printf -- '-name "%s" -o ' "$file"; done < fileList.txt |
sed 's/-o $/\n/')
ただし、ファイルが多すぎるとこの方法も中断されるため、一括で実行する必要があります。
for i in $(seq 1 100 $(wc -l < fileList.txt)); do
k=$((i+100));
printf 'find /mnt/SAN/documents/ -type f ';
sed -n "$i,${k}p" fileList.txt |
while IFS= read -r file; do
printf -- '-name "%s" -o ' "$file";
done | sed 's/-o $/\n/';
done
find
これにより、リスト内の100個のファイルの各バッチに対して別々のコマンドが生成され、上記のように実行するか、ファイルに保存eval
してそのファイルを実行できます。
for i in $(seq 1 100 $(wc -l < fileList.txt)); do
k=$((i+100));
printf 'find /mnt/SAN/documents/ -type f ';
sed -n "$i,${k}p" fileList.txt |
while IFS= read -r file; do
printf -- '-name "%s" -o ' "$file";
done | sed 's/-o $/\n/';
done > script.sh && bash script.sh > foundFiles.txt
気づくスティーブンの方法既存のファイルから始めて、欠落しているファイルを確認することはほぼ確実です(欠けているファイルよりも既存のファイルが多い場合を除く)。同様に、最初にすべての既存のファイルのリストを作成し、comm
それをターゲットファイルのリストと比較できます。 (ファイルリストがあると言ったので、ファイル名に改行文字が含まれていないとします。)
find /mnt/SAN/documents/ -type f | sort > found
comm -13 <(sort found) <(sort fileList.txt)
このコマンドは、にあるが、にないcomm
すべての行を印刷します。fileList.txt
found
答え4
200,000を超えるファイルのすべてのファイル名に対してfindを実行するのは非常に時間がかかります。私があなたならfind ${FILESROOT} > /tmp/SANfiles
逃げるでしょう。
for filename in $(cat my_database_files)
do
grep "${filename}" /tmp/SANfiles > /dev/null; r=${?}
if [ ${r} -eq 0 ]
then
echo ${filename} >> /tmp/existing_files
else
echo ${filename} >> /tmp/missing_files
fi
done
データベースのファイル名の形式に応じて、forループで変数名を変更したいかもしれませんが、私の考えの要旨は理解しているようです。