0

bash スクリプトに問題があります。2 つの cron タスクがあり、同じフォルダーからいくつかのファイルを取得してさらに処理します。

ls -1h "targdir/*.json" | head -n ${LIMIT} > ${TMP_LIST_FILE}
while read REMOTE_FILE 
do
    mv $REMOTE_FILE $SCRDRL
done < "${TMP_LIST_FILE}"
rm -f "${TMP_LIST_FILE}"

しかし、その後、スクリプトの 2 つのインスタンスが同時に実行され、インスタンスごとに異なる $SRCDRL に移動された同じファイルが実行されます。問題は、ファイルが別のスクリプトによって移動されないようにする方法です。

UPD: 多分私は少し不明確でした... json ファイルを保存するフォルダー "targdir" があります。そして、そのディレクトリからいくつかのファイルを取得して処理する 2 つの cron タスクがあります。たとえば、targdir に 25 個のファイルが存在する場合、最初の cron タスクは最初の 10 個のファイルを取得して /tmp/task1 に移動し、2 番目の cron タスクは次の 10 個のファイルを取得して /tmp/task2 に移動する必要がありますが、最初の 10 個のファイルは / に移動しますtmp/タスク 1 および /tmp/タスク 2。

4

3 に答える 3

1

2 つの cron ジョブが同じファイルを同じパスに移動するという事実は、そのうちの 1 つから得られるエラー (一方は成功し、もう一方は失敗する) に邪魔されない限り、問題にはなりません。

次を使用してエラーを無視できます。

    ...
    mv $REMOTE_FILE $SCRDRL 2>/dev/null
    ...
于 2013-10-21T14:30:00.470 に答える
1

スクリプトはリストから特定の数のファイルを移動することになっているため、2 つのインスタンスでせいぜい 2 倍のファイルを移動します。相互に干渉さえしない限り、移動されるファイルの数は少なくなる可能性があります。

いずれにせよ、これはおそらくまずまずの状況です。2 つのスクリプトが同時に実行されるのを防ぐ方法がある場合は、それを行う必要があります。

ただし、2 つのスクリプト インスタンスが同時に実行されるのを防ぐ方法がない場合は、少なくともスクリプトをエラーに対して強化する必要があります。

mv "$REMOTE_FILE" "$SCRDRL" 2>/dev/null

そうしないと、スクリプトはエラー出力を生成します (cron スクリプトでは良い考えではありません)。

さらに、あなたが両方のインスタンスで同じでないことを願っています(それを避けるために${TMP_LIST_FILE}使用できます)。$$そうしないと、この一時ファイルが上書きされ、最悪の場合、移動したくないパスを含むファイルが破損することになります。

于 2013-10-21T14:35:01.993 に答える
1

何よりもまず、名前の変更はアトミックです。ファイルを 2 回移動することはできません。ファイルが存在しないため、移動の 1 つが失敗します。スクリプトが並行して実行される場合、両方とも同じ 10 個のファイルをリストし、最初の 10 個のファイルが に移動され/tmp/task1、次の 10個のファイルが に移動されるのではなく、 /tmp/task24 個が に移動され/tmp/task1、6 個が に移動される場合があります/tmp/task2。あるいは、5 と 5、9 と 1、またはその他の組み合わせかもしれません。しかし、各ファイルは 1 つのタスクで終わるだけです。

したがって、何も間違っていません。各ファイルは 1 回だけ処理されます。ただし、一度に 10 個のファイルを処理できますが、5 個しか処理していないため、非効率的です。使用可能なファイルが十分にある場合に常に 10 個を処理するようにしたい場合は、同期を行う必要があります。基本的に 2 つのオプションがあります。

  1. リスト+コピーの周りにロックを配置します。flockこれは、 (1)とロック ファイルを使用して最も簡単に実行できます。それを呼び出す方法も 2 つあります。

    1. flock を介してコピー操作全体を呼び出します。

      flock targdir -c copy-script
      

      これには、除外する必要がある部分を別のスクリプトにする必要があります。

    2. ファイル記述子によるロック。コピーする前に、

      exec 3>targdir/.lock
      flock 3
      

      そしてそれがした後

      flock -u 3
      

      これにより、スクリプトの一部のみをロックできます。これは Cygwin では機能しません (しかし、おそらく必要ないでしょう)。

  2. 十分な量になるまで、ファイルを 1 つずつ移動します。

    ls -1h targdir/*.json > ${TMP_LIST_FILE}
    #                   ^^^ do NOT limit here
    COUNT=0
    while read REMOTE_FILE 
    do
        if mv $REMOTE_FILE $SCRDRL 2>/dev/null; then
            COUNT=$(($COUNT + 1))
        fi
        if [ "$COUNT" -ge "$LIMIT" ]; then
            break
        fi
    done < "${TMP_LIST_FILE}"
    rm -f "${TMP_LIST_FILE}"
    

    が失敗することがあります。その場合、ファイルが他のスクリプトによって移動されたために失敗したmvと仮定して、ファイルをカウントせずに次のファイルを移動しようとします。mv各スクリプトは多くのファイルをコピーし$LIMITますが、ランダムに選択される場合があります。

while余談ですが、ループで環境変数を設定する必要がまったくない場合は、一時ファイルなしで実行できます。単に:

ls -1h targdir/*.json | while read REMOTE_FILE
do
    ...
done

パイプラインの一部としてサブシェルで実行されるため、このようなループから変数を伝播することはできません。

環境変数を設定する必要があり、特にbashを使用して生活できる場合(私は通常、に固執しようとし/bin/shます)、次のように書くこともできます

while read REMOTE_FILE
do
    ...
done <(ls -1h targdir/*.json)

この場合、ループは現在のシェルで実行されますが、この種のリダイレクトは bash 拡張です。

于 2013-10-22T06:16:53.467 に答える