シェル スクリプトには次の内容が含まれています。
for file in $local_dir/myfile.log.*;
do
file_name=$(basename $file);
server_name=$(echo $file_name | cut -f 3 -d '.');
file_location=$(echo $file);
mv $file_location $local_dir/in_progress1.log
mysql -hxxx -P3306 -uxxx -pxxx -e "set @server_name='${server_name}'; source ${sql_script};"
rm $local_dir/in_progress1.log
done
基本的に、基準に一致するディレクトリ内のすべてのファイルを取得し、ファイル名からサーバー名を抽出してから、それを処理のために MySQL スクリプトに渡します。
私が疑問に思っているのは、完了までにそれぞれ 60 秒かかるファイルが 10 個あり、5 分後にシェル スクリプトの 2 番目のインスタンスを開始するかどうかです。
- a) 2番目のスクリプトは、まだ処理されていないファイルを参照しますか?
- b) ファイルを削除すると、まず問題が発生するか
それとも問題なく並行して実行できるでしょうか?
答え1
「60 秒」(または「5 分」) は、あくまでも適切な推定値であり、2 番目のバッチが開始されたときに最初のバッチがまだ進行中であるリスクがあると考えられます。バッチを分離する場合 (および、ログ ファイルが時々重複すること以外に問題がない場合)、進行中のファイルの命名規則の一部としてバッチ番号を作成する方がよい方法です。
このようなもの:
[[ -s ]] $local_dir/batch || echo 0 > $local_dir/batch
batch=$(echo $local_dir/batch)
expr $batch + 1 >$local_dir/batch
forループの前、そしてループの開始時に、パターンが実際のファイルと一致するかどうかを確認します。
[[ -f "$file" ]] || continue
ファイル名にバッチ番号を使用します。
mv $file_location $local_dir/in_progress$batch.log
衝突のリスクを軽減します。
答え2
上には問題に対する良い解決策がいくつか提示されていますが、私は少し説明したいと思います。なぜ何が問題なのか。
ほとんどの場合、名前を変更したログファイル(進行中のもの)が基準を満たしていない限り、おそらくこれを安全に実行できる最小限リスクがあります。それでもエラーは発生します...
ファイルのリストはスクリプトの実行時に生成されます。つまり、最終的に次のようになります。
Script A
のリストを取得します10 files
。処理を開始します。5 files
(残り 5) で、script B
のリストを取得し5 remaining files
、処理を開始します。Script a
次に、リストの次のファイル(処理を開始したファイルと同じscript B
)の処理に進みますが、ファイル名が変更されているためエラーになります。したがって、エラー処理を使用すると、理論的にはリストの次のファイルに移動して問題なく機能します。ただし、もちろん、常に星が揃う可能性はありますが、スクリプトが同じファイルに同時にアクセスし、予期しない事態が発生します。そのリスクはご自由にご判断ください。
よりエレガントな解決策としては、これをpython
スクリプトに変換し、parallel for loops
単一の for ループを作成してそれを並列に実行し、1 つのスクリプトで 2 つ以上の作業を実行できるようにする方法を検討することが考えられます。
答え3
別の方法としては、スクリプトに単純なバッチ キューを実装することです。
スクリプトの先頭では、次のようなことができます。
mkdir -p $localdir/batch
BATCHTMP=$(mktemp batch.XXXXXXXXXX)
MYBATCH="$localdir/batch/batch.$$"
# get list of current log files
find $local_dir/ -name 'myfile.log.*' > "$BATCHTMP"
# exclude any log files already in other batches
grep -vF -f <(sort -u $localdir/batch/batch.*) < "$BATCHTMP" > "$MYBATCH"
rm -f "$BATCHTMP"
# only process log files that are in my batch
for lf in $(cat "$MYBATCH") ; do
....
# somewhere in here, mv or rm the logfile being processed
# so it doesn't get processed again in a later batch run
done
rm -f "$MYBATCH"
もちろん、これは実行する必要があることの簡単な概要にすぎません。
ちなみに、これは、バッチ ファイルを生成してメイン スクリプトを実行するだけのラッパー スクリプトでも実行できます。