1

私は、ファイル システム A にあった数百万のファイルが実際にファイル システム B に移動されたことを確認する方法に取り組んできました。移動されました。ファイルは当初、ログを提供する rsync を介して移動されましたが、監査を行うのに役立つ形式ではありませんでした。そこで、システム A 上のすべてのファイルにインデックスを付けるために、次のスクリプトを作成しました。

#!/bin/bash
# Get directories and file list to be used to verify proper file moves have worked     successfully.
LOGDATE=`/usr/bin/date +%Y-%m-%d`
FILE_LIST_OUT=/mounts/A_files_$LOGDATE.txt
MOUNT_POINTS="/mounts/AA mounts/AB"

touch $FILE_LIST_OUT 
echo TYPE,USER,GROUP,BYTES,OCTAL,OCTETS,FILE_NAME > $FILE_LIST_OUT
for directory in $MOUNT_POINTS; do
    # format: type,user,group,bytes,octal,octets,file_name
    gfind $directory -mount -printf "%y","%u","%g","%s","%m","%p\n" >> $FILE_LIST_OUT

done

ファイルのインデックス作成は正常に機能し、約 3,000 万個のファイルのインデックス作成に約 2 時間かかります。

サイド B で問題が発生します。インデックス ファイルを読み取り、ファイルがそこにあるかどうかをテストし、そこにあるファイルの数をカウントする非常に単純なシェル スクリプトを作成しましたが、インデックス付きファイル名の 3,000 万行をループしている間にメモリが不足しています。 . while ループを介して以下のこの小さなコードを効果的に実行し、ファイルが見つかった場合と見つからなかった場合にカウンターをインクリメントします。

if [ -f "$TYPE" "$FILENAME" ] ; then
print file found 
++
else 
file not found 
++
fi

私の質問は次のとおりです。

  1. シェル スクリプトは、このような大きなリストからこの種のレポートを作成できますか。このスクリプトを実行しようとしたときに、64 ビットの UNIX システムでメモリが不足しました。より高速にするために、入力スクリプトを小さなチャンクに分割することを既に検討しました。現在、できる
  2. シェルスクリプトが不適切である場合、何を提案しますか?
4

4 に答える 4

1

rsync を使用したばかりですが、もう一度使用してください...

-- 既存のものを無視

これは、宛先に既に存在するファイルの更新をスキップするよう rsync に指示します (これは、既存のディレクトリを無視しないか、何も行われません)。--existing も参照してください。

このオプションは除外ではなく転送ルールであるため、ファイル リストに入るデータには影響せず、削除にも影響しません。受信者が転送を要求するファイルを制限するだけです。

このオプションは、中断されたバックアップ実行を続行する必要がある場合に、 --link-dest オプションを使用してバックアップを実行している場合に役立ちます。--link-dest の実行は (適切に使用された場合) 新しいディレクトリ階層にコピーされるため、 --ignore existing を使用すると、既に処理されているファイルが微調整されないことが保証されます (これにより、ハードリンクされたファイル)。これは、このオプションが宛先階層自体の既存のファイルのみを参照していることを意味します。

それは実際に問題を修正します(少なくとも、ファイル存在テストの差分リストが問題を修正できるのと同じ意味で。--ignore-existing手段を使用するとrsync、ファイル存在テストのみが実行されます(したがって、要求して使用すると差分リストが構築されます違いに関する情報だけが必要な場合は、 と を確認して--dry-runください--itemize-changes

2 つのディレクトリがあるfooとしbarます。、、、および のbar3 つのファイルが1ある2とし3ます。がファイルをbar含むディレクトリを持っているとしましょう。ディレクトリが空です:quz1foo

さて、結果ですが、

$ rsync -ri --dry-run --ignore-existing ./bar/ ./foo/
>f+++++++++ 1
>f+++++++++ 2
>f+++++++++ 3
cd+++++++++ quz/
>f+++++++++ quz/1

cd++++++++++には興味がないことに注意してrsyncくださいchdirfooでは、 calledにファイルを追加して、 (s)を削除するために1使用しましょう。grepchdir

$ rsync -ri --dry-run --ignore-existing ./bar/ ./foo/ | grep -v '^cd'
>f+++++++++ 2
>f+++++++++ 3
>f+++++++++ quz/1

fはファイルです。+++++++++は、ファイルが DEST ディレクトリに存在しないことを意味します

ここにボーナスがあります, remove --dry-run, そして、それは先に進み、あなたのために変更を加えます.

于 2013-02-26T21:34:26.453 に答える
0
  1. シェル スクリプトで 3000 万行のファイルを読み取ることはまったく問題ありません。プロセスが失敗した理由は、ファイル全体をメモリに読み込もうとしたことが原因である可能性が最も高いです。たとえば、for i in $(cat file). ファイルを読み取る正しい方法は次のとおりです。

    while IFS= read -r line
      do
        echo "Something with $line"
    done < someFile
    
  2. はい、シェルスクリプトは不適切です。diff ツールを使用する必要があります。

    diff -rNq /original /new
    
于 2013-02-26T21:22:08.697 に答える
0

解決策がスクリプトであることに特にこだわらない場合は、ディレクトリ ツリーを非常に簡単に比較できるmeldを調べることもできます。パターンがある場合は無視パターンを設定することもできます。

于 2013-02-26T21:37:01.890 に答える
0

ファイルのディレクトリを比較するkdiff3などのソリューションを検討しましたか?

バージョン 0.9.84 の機能に注意してください

Directory-Comparison: オプション "Full Analysis" を使用すると、ディレクトリ ツリー内の解決済みの競合と未解決の競合の数、またはデルタと空白の変更の数を表示できます。

于 2013-02-26T21:15:22.843 に答える