200,000を超えるファイルと異なる名前の出力を見つける方法

200,000を超えるファイルと異なる名前の出力を見つける方法

私たちは、多数のファイル(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.txtfound

答え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ループで変数名を変更したいかもしれませんが、私の考えの要旨は理解しているようです。

関連情報