どーも!marusukeです!
flockやexecを使った自動化スクリプトを書いていると必ず出てくる「ファイルディスクリプタ」について説明します!
ファイルディスクリプタとは
ファイルディスクリプタ(file descriptor、略してFD)は、プロセスが開いているファイルや入出力先を識別するために、OS(カーネル)が割り振る小さな整数番号のことです。「ファイル」といっても普通のファイルだけでなく、パイプ・ソケット・端末なども同じ仕組みで扱われます。
どのプロセスにも、起動した時点で最初から3つのFDが用意されています。
| 番号 | 名前 | 役割 |
|---|---|---|
| 0 | 標準入力(stdin) | キーボードなどからの入力 |
| 1 | 標準出力(stdout) | 通常の出力先(画面など) |
| 2 | 標準エラー出力(stderr) | エラーメッセージの出力先 |
この3つと、>や2>などのリダイレクト演算子との関係については、標準入出力とは?とリダイレクトの使い方で詳しく解説しています。この記事では、その先の「4番以降を自分で使う」方法を扱います。
プロセスIDとの違い
ファイルディスクリプタと混同しやすいのが、プロセスID(PID)です。この2つはまったく別の採番なので、区別しておきましょう。
- PID(プロセスID):OS上で動いているプロセスそれぞれに割り振られる番号。
psコマンドなどで見る、あの番号です。1つのプロセスにつき1つ。 - ファイルディスクリプタ番号:1つのプロセスの中で、「今このプロセスが開いているファイルや入出力先」を区別するための番号。0, 1, 2は標準入出力用に予約済みで、3番以降は自由に使えます。
例えるなら、PIDは「工場(プロセス)自体の工場番号」、ファイルディスクリプタは「その工場の中にある、番号のついた配管(0番配管・1番配管…)」です。同じプロセスの中でも、ファイルを開くたびに新しい配管(3番、4番…)を増やせます。
execで新しいファイルディスクリプタを開く使用例
1. execで4番以降のFDを開く
exec 200>/tmp/backup.lock
execをコマンドなしでリダイレクトだけに使うと、「このシェル(スクリプト)自体」に対してファイルディスクリプタを割り当てられます。ここでは200番を、書き込みモード(>)で/tmp/backup.lockというファイルに結びつけています。ファイルが存在しなければ自動的に作られます。200という数字自体に特別な意味はなく、標準入出力の0・1・2とぶつからないよう、大きめの番号を慣習的に使っているだけです。
2. 開いたFDへ書き込む
echo "処理を開始しました" >&200
>&200は「標準出力の代わりにFD200番へ出力する」という意味です。以降、このFDを通して/tmp/backup.lockに書き込めます(ただし、flockのロック用途であれば中身を使うことはほとんどなく、存在そのものが目印として使われます)。
3. FDを明示的に閉じる
exec 200>&-
>&-は「このFDを閉じる」という意味の記法です。もっとも、後述のとおりFDはプロセスが終了すれば自動的に閉じられるので、自動化スクリプトの中で明示的に閉じる場面はそれほど多くありません。
4. flockと組み合わせて排他制御に使う
#!/bin/bash
exec 200>/tmp/backup.lock
flock -n 200 || { echo "前回の処理が実行中のため終了します"; exit 1; }
# ここから先がロック取得後の処理
/home/ope/scripts/backup.sh
flockはファイルディスクリプタに対してロックをかけるコマンドです。そのため、ロックしたい対象をexecであらかじめFDとして開いておく必要があります。詳しい動きはflockコマンドの使い方で解説しています。
execによるFD操作の書き方
| 書き方 | 意味 |
|---|---|
exec N>ファイル | FD番号Nを書き込みモードでファイルに割り当てる(ファイルは上書きされる) |
exec N>>ファイル | FD番号Nを追記モードでファイルに割り当てる |
exec N<ファイル | FD番号Nを読み込みモードでファイルに割り当てる |
exec N>&- | FD番号Nを閉じる |
コマンド >&N | コマンドの標準出力をFD番号Nへ出力する |
コマンド <&N | コマンドの標準入力をFD番号Nから読み込む |
補足:ファイルディスクリプタは、そのプロセスが終了する(または明示的に閉じる)と自動的に解放されます。flockコマンドやtrapコマンドを使った自動化スクリプトで、ロックの解放処理を明示的に書かなくても事故が起きにくいのはこのためです。
関連コマンド
標準入出力の基本は標準入出力とは?、>や<によるリダイレクトはリダイレクトの使い方をご覧ください。ここで開いたFDを使った多重起動対策はflockコマンドの使い方、スクリプト終了時の後片付けはtrapコマンドの使い方で解説しています。
まとめ
ファイルディスクリプタは、プロセスが開いているファイルや入出力先を識別するための番号です。標準入出力用の0・1・2に加えて、execを使えば4番以降を自分で開いて自由に使えます。プロセスID(PID)とは別物であること、プロセス終了時に自動的に閉じられることを押さえておけば、flockを使った排他制御のスクリプトもぐっと理解しやすくなります。
以上です! ここまで読んでいただきありがとうございました!
https://marusuke-blog.com/linux-stdin-stdout-stderr/ https://marusuke-blog.com/linux-redirection/ https://marusuke-blog.com/linux-command-flock/ https://marusuke-blog.com/linux-command-trap/

コメント