ファイル記述子移動の実際の使用

ファイル記述子移動の実際の使用

Bashのマニュアルページによると:

リダイレクト演算子

   [n]<&digit-

ファイル記述子をファイル記述子に移動するdigitか、指定されていない場合はn標準入力(ファイル記述子0)に移動します。コピー後に閉じます。ndigitn

あるファイル記述子を別のファイル記述子に「移動」することはどういう意味ですか?この慣行の一般的な状況は何ですか?

ベストアンサー1

3>&4-bashもサポートするksh93の拡張です。3>&4 4>&-今、3の略語は4があった位置を指し、4は今閉じているので、4が指すのは3に移動しました。

一般的な使用法は、コピーを作成または保存してstdin復元したい場合です。たとえば、次のようになります。stdout

変数にstdoutだけを残して、コマンドのstderr(およびstderrのみ)をキャプチャするとします。

コマンド置換はvar=$(cmd)パイプラインを生成します。パイプの書き込みの終わりはcmdstdout(ファイル記述子1)になり、もう一方の端はシェルから読み込まれ、変数が入力されます。

stderrここで変数にアクセスするには、次のようにしますvar=$(cmd 2>&1)。 fd 1(stdout)と2(stderr)の両方がパイプに入り(最終的に変数に入る)、これは私たちが望むものの半分です。

これによりvar=$(cmd 2>&1-)(略語でvar=$(cmd 2>&1 >&-cmdstderrだけがパイプに入り、fd1は閉じます。cmd出力を書き込もうとするとエラーが返されます。EBADFファイルを開くと、最初の利用可能なfdが得られ、stdoutコマンドがそれを防止しない限り、開いたファイルがここに割り当てられます。私たちが望むものではありません。

stdoutが独立した状態を維持するようにするにはcmd、つまり、コマンド置換の外部で指す同じリソースを指すようにするには、何らかの方法でそのリソースをコマンド置換内にインポートする必要があります。これを行うには、次のコピーを作成できます。stdout 外部コマンド置換はそれを内部に入れます。

{
  var=$(cmd)
} 3>&1

もっと簡潔に書く方法は次のとおりです。

exec 3>&1
var=$(cmd)
exec 3>&-

(これは最終的にfd 3を閉じるのではなくfd 3を復元する利点もあります)。

{次に(またはexec 3>&1)、}fd 1と3はどちらもfd 1が元のポイントと同じリソースを指します。 fd 3はまた、コマンド置換内の対応するリソースを指します(コマンド置換はfd 1、stdoutのみをリダイレクトします)。したがって、上からcmdfds 1、2、3 を取得します。

  1. varによるパイプ
  2. 影響を受けない
  3. 命令置換以外を指す1と同じ

次のように変更すると:

{
  var=$(cmd 2>&1 >&3)
} 3>&1-

これにより、次のようになります。

  1. 命令置換以外を指す1と同じ
  2. varによるパイプ
  3. 命令置換以外を指す1と同じ

今私たちは欲しいものを手に入れました。 stderrはパイプに入り、stdoutは変更されていません。しかし、我々はfd 3をcmd

コマンドは通常、fd 0から2までがオープンで標準入力、出力、エラーであると仮定しますが、他のfdについては何も仮定しません。彼らはfd 3を変更せずに維持する可能性が高い。他のファイル記述子が必要な場合は、最初open()/dup()/socket()...に使用可能なファイル記述子を返す操作を実行するだけです。 (シェルスクリプトなどexec 3>&1)特別に使用する必要がある場合は、fdまずそれを何かに割り当てます(そしてその過程でfd 3が保持しているリソースはそのプロセスによって解放されます)。

fd 3を閉じることは使用しないので良い習慣ですがcmd、呼び出す前に割り当てられたままにしておくことは大きな問題ではありませんcmd。問題は、プロセスcmd(および作成できる他のプロセス)に利用可能なfdが少ないことです。潜在的に深刻な問題は、fdが指すリソースを最終的にcmdバックグラウンドプロセスによって生成されたプロセスによって保持できるかどうかです。これは、リソースがパイプまたは他のプロセス間通信チャネル(スクリプトが実行時に実行されている場合script_output=$(your-script))の場合に問題を引き起こす可能性があります。これは、もう一方の端から読み取るプロセスがファイルの終わりを見ることができないことを意味します。最後までリソース。バックグラウンドプロセスが終了します。

したがって、ここでは次のように書くことをお勧めします。

{
  var=$(cmd 2>&1 >&3 3>&-)
} 3>&1

そのうち with はbash次のように短縮できます。

{
  var=$(cmd 2>&1 >&3-)
} 3>&1

ほとんど使用されない理由をまとめると、次のようになります。

  1. 非標準で、単にフレーズ砂糖です。これらの一般的な機能に慣れていない人にとって、スクリプトの移植性を低下させ、あまり明確にすることと、いくつかのキーストロークを保存することのバランスを取る必要があります。
  2. コピー後に元のfdを閉じる必要性はほとんど見落とされることがよくあります。ほとんどの場合、結果が発生しないため、または>&3代わりに実行されるからです。>&3->&3 3>&-

ほとんど使用されていないことを証明してください。バッシュから偽。 Bashからcompound-command 3>&4-またはfd 4を離れると、返されたany-builtin 3>&4-後も閉じます。 ㅏcompound-commandany-builtin修理するこの問題は現在(2013-02-19)解決することができます。

おすすめ記事