デフォルトでは、ファイル記述子はexec関数全体で開いたままです。記述子0〜2の利点はおそらく理解できます。しかし、他の記述子を開いたままにしておくための実用的なユースケースはありますか?この事実に依存する実際のアプリケーションはありますか?
実行されたコマンドにfdを渡したくない場合は、ファイル記述子に設定できるフラグがあります(open()
:O_CLOEXEC以降はfcntl()
:FD_CLOEXECを使用)。
コマンドを実行する場合は、内部ファイル記述子に対してこれを行う必要があります。
シェルでは、たとえば、_ksh93
_を実行すると、_exec 3< some-file
_がそのようになります。 _{ cmd1; cmd2; } 3< file
_で開かれた他のシェルまたはfdsの場合、_cmd1
_または_cmd2
_がそのfd:_{cmd1 3<&-; cmd2; } 3< file
_にアクセスしないようにするには、手動で閉じる必要があります。 これは良い習慣ですが、実行しなくても通常は重要ではないため、常に実行されるわけではありません 。
さて、この機能が役立つかどうか。はい、いくつかのコマンドはそれに依存しています。
いくつかのコマンドは、呼び出し元によって開かれたことを意図した引数としてファイル記述子を受け取ります。頭に浮かぶいくつかの例:
xterm
とその_-S
_オプションqemu
さまざまなものflock
(呼び出し元のfdでファイルをロックするため)test
コマンド別名_[
_は_-t
_オプションです(test
ユーティリティは最近のほとんどのBourneのようなシェルに組み込まれていますが、test
コマンドを実行できます)。dialog
は、ユーザーからの入力、ユーザーへの出力とエラー、および呼び出し元への入出力にファイル記述子を必要とするため、そのために追加のfdsを使用できます。gpg
またはopenssl
にファイル記述子を指定して、パスフレーズまたはその他の情報を伝達できます。helperユーティリティは多数あります(たとえば、executeコマンドの一部を、それに依存するsetuid/setgid実行可能ファイルを使用して別のユーザーまたはグループとして実行することができます。
プロセスの置換はそれに依存しています。
In diff <(cmd1) <(cmd2)
では、2つのファイル記述子(パイプへ)がdiff
に渡され、diffは引数として渡された特別な/ dev/fd/nを介してそれらにアクセスすることによりアクセスします。
プロセス置換のないシェルの場合は、次のようなものを手作業で行います。
_cm1 | { cmd2 | diff /dev/fd/3 -; } 3<&0
_
TinyMUSHとおそらくその兄弟および子コードベースの多くは、execのこの機能を使用して非常に効果的です。ユーザーを接続したまま、サーバーを再起動するコマンドを発行し、完全に新しいバイナリにアップグレードすることができます。
これは、ファイル記述子を含む、接続されている各ユーザーに関する小さな情報のdbを書き込むことによって行われます。新しく実行されたTinyMUSHのコピーは再起動データベースを読み取り、接続しているユーザーの知識を復元し、中断したところから再開します。
最終結果:ユーザーに見える一時停止のみで新機能がリリースされます。
Nginxは、接続を失うことなく、バイナリアップグレードを行うのと多少似ています。
接続されたソケットは、この方法で子プロセスに渡すことができます。たとえば、着信接続を受け入れるネットワークサーバーは、それらの処理を別のプロセスに完全に渡すことができます。
ユビキタスな例については、 inetdのソースコード を参照してください。