質問

の修正バージョン シェルスクリプト オーディオ ファイルを FLAC から MP3 形式に変換します。このコンピューターにはクアッドコア CPU が搭載されています。スクリプトは以下を使用して実行されます。

./flac2mp3.sh $(find flac -type f)

これにより、FLAC ファイルが変換されます。 flac ディレクトリ (ファイル名にスペースは含まれません) を MP3 ファイルにコピーします。 mp3 ディレクトリ (と同じレベル) flac)。宛先の MP3 ファイルがすでに存在する場合、スクリプトはそのファイルをスキップします。

問題は、スクリプトの 2 つのインスタンスがほぼ同時に同じ MP3 ファイルの存在をチェックすることがあり、結果として MP3 ファイルが破損してしまうことです。

各コマンドラインで異なるファイルセットを指定したり、作業を上書きしたりせずに、スクリプトを複数回 (つまり、コアごとに 1 回) 実行するにはどうすればよいでしょうか?

アップデート - 最小限の競合状態

このスクリプトは次のロック メカニズムを使用します。

  # Convert FLAC to MP3 using tags from flac file.
  #
  if [ ! -e $FLAC.lock ]; then
    touch $FLAC.lock
    flac -dc "$FLAC" | lame${lame_opts} \
      --tt "$TITLE" \
      --tn "$TRACKNUMBER" \
      --tg "$GENRE" \
      --ty "$DATE" \
      --ta "$ARTIST" \
      --tl "$ALBUM" \
      --add-id3v2 \
      - "$MP3"
    rm $FLAC.lock
  fi;

ただし、それでも競合状態が残ります。

役に立ちましたか?

解決

「lockfile」コマンドは、競合状態を発生させずにシェル スクリプトに対して実行しようとしている内容を提供します。このコマンドは、特にこの種の目的のために procmail 担当者によって作成され、ほとんどの BSD/Linux システムで利用できます (procmail はほとんどの環境で利用できるため)。

テストは次のようになります。

lockfile -r 3 $FLAC.lock
if test $? -eq 0 ; then
  flac -dc "$FLAC" | lame${lame_opts} \
    --tt "$TITLE" \
    --tn "$TRACKNUMBER" \
    --tg "$GENRE" \
    --ty "$DATE" \
    --ta "$ARTIST" \
    --tl "$ALBUM" \
    --add-id3v2 \
    - "$MP3"
fi
rm -f $FLAC.lock

あるいは、lockfile が無期限に再試行を続けるようにすることもできるため、戻りコードをテストする必要がなく、代わりに出力ファイルをテストして flac を実行するかどうかを判断できます。

他のヒント

持っていない場合 lockfile そしてそれをインストールすることはできません(どのバージョンでも - いくつかの実装があります)堅牢で移植可能なアトミックミューテックスは mkdir.

作成しようとしているディレクトリがすでに存在する場合は、 mkdir 失敗するので、それを確認できます。作成が成功すると、コードと同時に他の連携プロセスがクリティカル セクションに存在しないことが保証されます。

if mkdir "$FLAC.lockdir"; then
    # you now have the exclusive lock
    : critical section
    : code goes here
    rmdir "$FLAC.lockdir"
else
    : nothing? to skip this file
    # or maybe sleep 1 and loop back and try again
fi

完全を期すために、おそらく次のものも探してください flock それが確実に利用できる一連のプラットフォームを使用していて、パフォーマンスの高い代替手段が必要な場合 lockfile.

作業中の FLAC ファイルのロックを実装できます。何かのようなもの:

if (not flac locked)
  lock flac
  do work
else
  continue to next flac

出力を一意の名前を持つ一時ファイルに送信し、ファイルの名前を目的の名前に変更します。

flac -dc "$FLAC" | lame${lame_opts} \
      --tt "$TITLE" \
      --tn "$TRACKNUMBER" \
      --tg "$GENRE" \
      --ty "$DATE" \
      --ta "$ARTIST" \
      --tl "$ALBUM" \
      --add-id3v2 \
      - "$MP3.$$"
mv "$MP3.$$" "$MP3"

競合状態がファイル ロック システムを通じて時々漏洩したとしても、最終出力は依然として 1 つのプロセスの結果になります。

ファイル プロセスをロックするには、.lock 拡張子が付いた同じ名前のファイルを作成します。

エンコードを開始する前に、.lock ファイルの存在を確認し、必要に応じて、ロックファイルの日付が古すぎないことを確認します (プロセスが停止した場合に備えて)。存在しない場合は、エンコードの開始前に作成し、エンコードの完了後に削除します。

ファイルをフロックすることもできますが、これは flock() を呼び出してファイルに書き込み、閉じてロックを解除する c でのみ機能します。シェル スクリプトの場合は、ファイルの書き込みを行うために別のユーティリティを呼び出している可能性があります。

Makefileを書いてみてはどうでしょうか?

ALL_FLAC=$(wildcard *.flac)
ALL_MP3=$(patsubst %.flac, %.mp3, $(ALL_FLAC)
all: $(ALL_MP3)
%.mp3: %.flac
        $(FLAC) ...

それならそうする

$ make -j4 all

bash では、ファイルの上書きを避けるために noclobber オプションを設定することができます。

設定をヘルプ| egrep 'noclobber | -c'

次のようなツールを使用します FLOM (フリーロックマネージャー) そして、以下のようにコマンドをシリアル化するだけです。

flom -- flac ....
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top