どーも!marusukeです!
ファイルロックを使って、同じ処理が同時に複数実行されるのを防ぐコマンドflockについて説明します!
flockコマンドでできること
flock [オプション] <ロックファイル> <コマンド> [引数...]
flock [オプション] <ロックファイル> -c "<コマンド>"
flock [オプション] <ファイルディスクリプタ番号>
flockは、指定したファイルに対して排他ロック(または共有ロック)をかけ、そのロックが取得できている間だけコマンドを実行するためのコマンドです。
自動化スクリプトをcronで定期実行していると、「前回の処理がまだ終わっていないのに、次の実行が始まってしまう」という事故が起こりがちです。バックアップ処理が長引いているところに次のcronが走り出すと、同じファイルに同時に書き込みが発生して壊れてしまう、といったケースですね。flockはこの多重起動を防ぐための定番コマンドです。
flockコマンドの使用例
1. 基本形:ロックを取得してコマンドを実行
flock /tmp/backup.lock -c "/home/ope/scripts/backup.sh"
/tmp/backup.lockというファイルに対してロックを取得し、成功したらbackup.shを実行します。ロックファイルは中身を使うわけではなく、存在そのものが「今誰かが処理中かどうか」の目印として使われます。ファイルが無ければflockが自動的に作成します。
2. ノンブロッキングモード:実行中なら即座に終了する
flock -n /tmp/backup.lock -c "/home/ope/scripts/backup.sh"
デフォルトのflockは、ロックが取得できるまで待ち続けます。cronでの多重起動対策としては「待つ」のではなく「今回はあきらめて終了する」方が安全なことがほとんどなので、-n(--nonblock)をセットで使うのが定番です。
3. スクリプト内でファイルディスクリプタを使う書き方
#!/bin/bash
exec 200>/tmp/backup.lock
flock -n 200 || { echo "前回の処理が実行中のため終了します"; exit 1; }
# ここから先がロック取得後の処理
/home/ope/scripts/backup.sh
exec 200>ファイルでファイルディスクリプタ200番にロックファイルを割り当て、flock -n 200でそのディスクリプタに対してロックを取得します。この書き方なら、スクリプトが終了(正常・異常問わず)した時点でファイルディスクリプタが自動的に閉じ、ロックも解放されるのが利点です。-cで外部コマンドを呼ぶよりも、スクリプトに組み込みやすい形です。
4. cronに登録する例
*/10 * * * * /usr/bin/flock -n /tmp/sync.lock /home/ope/scripts/sync.sh
10分ごとに同期スクリプトを実行しつつ、前回の実行がまだ終わっていなければ今回はスキップする、という設定です。処理時間が読みにくいバッチ処理をcronに登録するときは、まずこの形にしておくと事故が減ります。
主なオプション
| オプション | 説明 |
|---|---|
-n, --nonblock | ロックが取得できない場合、待たずに即座に失敗して終了する |
-w, --timeout <秒> | 指定した秒数だけロック取得を待ち、それでも取得できなければ失敗する |
-x, --exclusive | 排他ロックを取得する(デフォルトの動作) |
-s, --shared | 共有ロックを取得する(複数プロセスで同時に読み取り目的で保持できる) |
-u, --unlock | 保持しているロックを明示的に解放する |
-c, --command <コマンド> | シェル経由で1つのコマンド文字列を実行する |
補足:
-nをつけずに使うと、待っている間ずっとプロセスが残り続けます。cronの多重起動対策として使う場合は、基本的に-nか-wをセットで指定しておくのがおすすめです。
関連コマンド
定期実行そのものについてはcrontabコマンドの使い方、スクリプト終了時の後片付けについてはtrapコマンドの使い方もあわせてご覧ください。
まとめ
flockは、ファイルロックの仕組みを使ってコマンドの多重起動・重複実行を防ぐためのコマンドです。cronで自動化スクリプトを回している方は、-nオプションとセットで使うことを覚えておきましょう。
以上です! ここまで読んでいただきありがとうございました!
https://marusuke-blog.com/linux-command-crontab/
https://marusuke-blog.com/linux-command-trap/
https://marusuke-blog.com/linux-command-at/

コメント