flock はファイル(またはディレクトリ)に共有/排他ロックを取得し、そのロックを保持したままコマンドを実行できるユーティリティです。スクリプトの多重起動防止や、並列処理のクリティカルセクション保護に使われます。ロック対象が存在しない場合は作成されます。(man7.org, EuroLinux)
構文(Syntax)
# 形式1: ロック対象を指定してコマンドを実行
flock [OPTIONS] FILE|DIR COMMAND [ARG...]
# 形式2: シェルの FD をロック(exec 等で FD を開いてから)
flock [OPTIONS] FD
# 便利形: 文字列でコマンドを渡す
flock [OPTIONS] FILE|DIR -c 'SHELL_COMMANDS'
- 既定は排他ロック。共有ロックは
-s。取得できない場合は待機します(-nで即時失敗)。(man7.org)
主なオプション一覧
| オプション | 説明 | 使用例 |
|---|---|---|
-s, --shared | 共有ロック(読取側など複数可) | flock -s /tmp/data.lock -c 'cat data' (man7.org) |
-x, --exclusive (-e 同義) | 排他ロック(書込側1つのみ、既定) | flock -x /var/lock/job.lock myjob (man7.org) |
-n, --nonblock | 取得できなければ即時失敗 | flock -n /tmp/backup.lock -c './backup' (man7.org) |
-w, --timeout SEC | タイムアウト秒を指定 | flock -w 30 /tmp/lock -c 'do_slow' (man7.org) |
-E, --conflict-exit-code N | 競合時の終了コードを N に | flock -n -E 100 /tmp/lock cmd (ManKier) |
-o, --close | コマンド実行前にロックFDを閉じる(子プロセスへロックを継承させない用途) | flock -o /tmp/lock -c 'spawn-children' (ManKier) |
-F, --no-fork | フォークせずに直接コマンドを実行(--closeと非両立) | flock -F /tmp/lock cmd (ManKier) |
-c 'CMD' | コマンド文字列をシェルに渡す | flock /tmp/l -c 'echo hi; sleep 1' (man7.org) |
-u, --unlock | 明示的にアンロック(FDモードで使用) | flock -u 200 (man7.org) |
-v, --verbose / -h, --help / -V, --version | 逐次ログ / ヘルプ / バージョン | flock -v -n /tmp/lock true (man7.org) |
-oは「実行前に FD を閉じる」ため、子プロセスにロックを持たせたくない場合に有用です。--no-fork(-F)と同時指定は不可です。(ManKier)
実行例
多重起動を防ぐ(即時失敗)
説明: すでに動作中なら即終了(終了コード 1 など)。
コマンド:
flock -n /var/lock/myjob.lock -c '/usr/local/bin/myjob'
echo "exit=$?"
出力例(ロック獲得失敗時):
exit=1
(-E で任意コードに変更可) (man7.org, ManKier)
cron で“かぶり”を防止
説明: 1分おきでも重ならないように。
コマンド(crontab 行):
*/1 * * * * flock -n /tmp/backup.lock -c '/usr/local/sbin/backup'
(ex1-lab)
FD モードでクリティカルセクションを囲む(シェル)
説明: スクリプト全体でロックを保持。
コマンド:
exec 200>/var/lock/task.lock # FD=200 を開く(存在しなければ作成)
flock -n 200 || { echo "busy"; exit 1; } # 取れなければ即終了
# ここからクリティカルセクション
update_db
generate_report
flock -u 200 # 明示的にアンロック(終了時にFDが閉じられても解除されます)
共有ロックで“読み手”を並列許可
説明: 読み取り処理は並行、書き込みは別途排他ロックで制御。
コマンド:
flock -s /tmp/data.lock -c 'cat bigdata.csv | wc -l'
(man7.org)
ディレクトリをロック対象にする
説明: ファイルだけでなくディレクトリにもロックできます。
コマンド:
flock -w 10 /var/lock/myapp 'sh -c "touch /tmp/doing; sleep 2"'
エラー例:--no-fork と --close の併用
説明: 併用するとロックを保持するプロセスがなくなるためエラー。
コマンド:
flock -F -o /tmp/lock -c 'echo NG'
出力例(例): オプション不正のエラー
根拠: 両者は非両立です。(ManKier)
関連コマンド
flock(2): カーネルのアドバイザリロックAPI。NFS などでの挙動差の説明もこちらにあり。(man7.org)fcntl(2): POSIX レコードロック(NFS での相互運用に利用)。(man7.org)lockfile(procmail)/setlock(daemontools): ロックファイルを用いる別系統の直列化ツール。mkdirの原子作成を使う簡易ロック:手軽だが解除漏れ検知などは自前実装が必要。
備考
- アドバイザリ:
flockのロックは協調的(アドバイザリ)です。ロックを無視して I/O することも可能なので、協調する全プロセスでflockなど同一方式を用いてください。(man7.org) - NFS / ネットワークFS: Linux 2.6.12 以降の NFS クライアントでは、
flock()が fcntl のバイト範囲ロックでエミュレートされ、相互に干渉します(排他は書き込み用にオープンが必要)。古い環境・他実装では非対応/局所動作のことがあるため注意。(Arch Linux マニュアルページ) - ディスクリプタ継承:
forkで複製された子は同じロックを保持できます。子にロックを持たせたくない場合は--closeを検討。(ManKier, ウィキペディア) - ロック対象の種類: ファイル/ディレクトリどちらでも可。対象が無ければ作成されます。(EuroLinux)
- 終了コード: 競合で失敗した場合は既定で 1 を返します(
-Eで変更可)。-nなしでは待機します。(man7.org, ManKier)
参考
- man7.org
flock(1)(util-linux): https://www.man7.org/linux/man-pages/man1/flock.1.html - util-linux
flock(1)(別ミラー): https://man.docs.euro-linux.com/EL%207/util-linux/flock.1.en.html - man7.org
flock(2)(NFS での挙動等): https://man7.org/linux/man-pages/man2/flock.2.html - Mankier
flock(1)(--no-fork/--closeの補足): https://www.mankier.com/1/flock - FreeBSD
flock(1)(BSD 実装の書式): https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=1 - 日本語man(Linux JM): https://linuxjm.sourceforge.io/html/util-linux/man1/flock.1.html
- 使いどころの例(cron での多重起動防止): https://ex1.m-yabe.com/archives/7849

コメント