fd 3 を使用するのは安全ですか?

fd 3 を使用するのは安全ですか?

プロセス置換を使用せずに複数の出力パイプなどの操作を実行するためにこれを使用する質問がいくつかあります。

これには固定のfd番号を使用するだけで安全ですか?プログラムがすでに説明どおりにそれを使用している可能性はありますか?ここ重要なものを上書きしたり、関係のないものを読んだりするのでしょうか?

答え1

プログラムがすでにそれを使用している可能性はありますか

いいえ。I/O リダイレクトは、プログラムまたはスクリプトが開始される前に発生します。

通常、プログラムまたはスクリプトが起動すると、標準記述子 (0/標準入力、1/標準出力、2/標準エラー) のみが開きます。(これらは、端末、デバイス、ファイル、またはネットワーク ソケットを参照する場合がありますが、開いていることが想定されています。1 つを「閉じる」代わりに、不要な記述子を から/にリダイレクトします。/dev/null基本的に「どこにも」/「何も」ありません。)

プログラムは、空きディスクリプタを使用するようなシステムコールを介してディスクリプタを使用しますopen。つまり、カーネルにファイルやソケットを開くように要求しません。特定の記述子にカーネルが記述子を選択します。したがって、プログラムが追加の記述子を使用する唯一のケースは、プログラムの起動時に既に開いていることが予想される場合です。このようなユーティリティ デーモンはまれに存在します。これらのデーモンは、標準の記述子に加えて、たとえば、起動時に記述子 3 が開いている場合は、それが管理サービス (ま​​たは同様のサービス) に接続されていると予想します。

プログラムがハードコードされた記述子を使うことに決めた場合(そしてそれが唯一の理由であるのは、それが別のプログラムをフォークして実行するからである)、期待するプログラムがその記述子を何らかの用途で使用したい場合、すでに開いている記述子は閉じられます (前述したように、これは非常にまれです)。(ちなみに、プログラムがdup2()POSIXy システムなどで特定の記述子を使用することを示すと、カーネルが閉じます。プロセスは気にする必要はありません。)

シェル スクリプト (Bash および sh) は固定の記述子番号を使用するため、スクリプトが特定の記述子を使用して入出力リダイレクトを行う可能性があります。ただし、その場合、スクリプトは記述子が閉じられていると想定するため、以前のリダイレクトは単に無視され、効果はありません。(記述子が開いていて、スクリプトがその記述子を内部的なものに使用する場合、スクリプトがそれをリダイレクトするときに、元の記述子はカーネルによって、および前の段落で述べた理由により、最初に閉じられます。何らかのデータ漏洩が発生するには、スクリプトが特別に次のことを行う必要があります。テスト記述子がすでに開かれている場合、避けるリダイレクトします。

また、Fortran I/O ユニットまたはチャネルは、識別に番号を使用する場合でも、記述子とは関連がないことに注意してください。したがって、Fortran プログラムがユニット 10 を使用する場合でも、記述子 10 を使用することを意味するわけではありません。

これには固定の fd 番号を使用するだけで安全ですか?

はい。POSIX では、プログラムは少なくとも 20 個の記述子を開くことができると規定されているため、3 から 19 までの任意の固定数であれば問題なく動作するはずです。

重要な点は、スクリプトの場合はスクリプトの冒頭に短いコメントを記述し、プログラムの場合は使用方法 (-hまたは--helpコマンドライン オプション) とマニュアル ページに記述して、適切に文書化することです。

スクリプトの場合、競合が発生した場合 (競合が発生した場合は、上で説明したように、「プログラムが起動するとすぐにパイプが閉じるため、スクリプトがまったく機能しない」という種類の競合になります)、ユーザーは固定の記述子番号を変更して、ニーズに合わせることができます。したがって、スクリプト作成者としてのあなたの仕事は、事前に計画を立て、後続のユーザーがそれを簡単にできるようにすることです。(意図と全体的な設計を説明する明確なコメントで十分です。記述子番号を変数にしたり、スクリプトが行うすべての小さなアクションを説明する必要はありません。)

プログラムの場合、実行時に構成可能にしておくのがよいでしょう。たとえば、プログラム/デーモンが、グラフィカル ユーザー インターフェイスを使用した特別な制御プロトコル用に、開いている場合は記述子 3 を使用するように設定できます。ただし、'-c 5' などのコマンド ライン オプションを使用すると、名前付き記述子 (または、または、指定されたファイル、名前付きパイプ、またはローカル ドメイン ソケット) を使用でき-c /dev/nameます-c named-pipe-c :socketpath この方法により、ユーザーはスクリプトとの競合を簡単に回避できます。

関連情報