はじめに

シェルスクリプトでAtomicなファイル操作が必要になる例を次の2点あげ、どのコマンドを使用すればいいのか記載する。

  • ロックファイルの作成
  • 複数のプロセスが複数のファイルを処理する

ロックファイルの作成をシェルスクリプトで実現する方法

ロックファイルを使いたいということは、複数プロセスからロックファイルの存在確認と(存在しない場合)ファイル作成が行われるということなので、存在確認と作成を同時にAtomicに行ってくれるコマンドが必要になる。

シンボリックリンクを作成するコマンドが適任だ。

シンボリックリンクは、すでにファイルが存在するとエラーとなる。シンボリックリンクをロックファイルとして扱えば、ロックファイルが存在すればエラーが発生し、存在しなければシンボリックリンクとして作成される。さらにシンボリックリンクの都合のいいことは、リンク先のファイルが存在しなくてもいいということだ。適当な文字列をリンク先としておけばいい。1でもいいし、$$としてシェルスクリプトのプロセスIDでもいい。

if ! ln -s $$ file.lock; then
    exit 0
fi

ロックファイルについては、以下でも取り上げている。

参考: シェルスクリプトでのロックファイル作成のベストプラクティス

複数のプロセスが複数のファイルを処理する

複数のプロセスが複数のファイルを処理していく、という題材。ロックファイルを使用してもいいのだが、Atomicなファイル操作さえできればロックファイルを使用しなくても実現できる。

あるディレクトリにファイルが大量にあり、各プロセスはループして次々とファイルを処理していく場合、プロセス間で処理するファイルがぶつからないようにする必要がある。この場合、ロックファイルを作成して、処理対象のファイルを決める瞬間を一プロセスに限定するというような処理を書いてもいいが、mv コマンドを使用すればロックファイルを使用するまでもない。

mv コマンドは、移動元と移動先が同一ファイルシステム上にある場合、rename()システムコールが呼ばれるが、renameはAtomicにファイルの置き換えを行ってくれる。

処理対象のファイル名が(a.txt, b.txt, ...)だった場合、 mv a.txt a.txt.done とすれば、複数のプロセスが同時にa.txtを触ることはできなくなる。mv に成功したプロセスのみa.txtを処理することができ、失敗したプロセスは次のファイルを mv してみればいい。