ファイル記述子をよりよく理解するために使用しようとしていますが、次の内容を理解できません。
$ grep "..." 3>&1 1>/dev/null
1
12
13
123
321
3
上記はシェルで一致するものを表示しません。これは/dev/nullにリダイレクトされるため、明らかに発生します。私が理解していないのは、3>&1
fd 3にコピーした後に出力を見続けるためにこれを行うべきではありません。
私は何を見逃していますか?
ベストアンサー1
あなたのリダイレクトするFD 3をFD 1のコピーにし、FD 3がstdoutなどを指します。それに書く(デフォルトでは)TTYに移動します。これによりFD 1がにリダイレクトされるため、/dev/null
FD 1に記録されているすべての内容は削除されます。grep
FD 3は記録されていないため、目に見える何も起こりません。
順番に発生します。まずコピー(dup2
)はFD 3を指すので、FD 3はこれからFD 1が現在指していることを指し、FD 1はを指すポインタに置き換えられます/dev/null
。
最終結果を図に示す。下図のように:
標準エラー(ピンク、FD 2)とFD 3はTTYに送信され、標準出力はに送信されます/dev/null
。 FD 3はコピー時にFD 1が指す場所なので、まだTTYを指します。ただし、このgrep
コマンドはFD 3に何も書き込もうとしないため、コピーはまったく使用されません。
「コピー」は方向性です。3>&1
処理後にFD 3に記録された内容はすべて、処理時にFD 1が指す位置に移動します。それ以上は「保存」しません。その後、FD 1をリダイレクトすると、ここに記録されているすべてのコンテンツが新しい場所に移動されます。実行する作業は、後で使用したい場合に備えて、FD 1の元の宛先に保持されます。grep
標準出力の最終位置に影響を与える唯一のリダイレクトは、どこに行くかを明示的に通知する1>...
リダイレクトです。
もしgrep
はいFD 3を作成すると、期待どおりに端末に表示されます。通常、FD 1 にのみ出力されるため、実際の出力はすべて破棄されます。
必要に応じて、FD 3にgrep出力を作成できます。
( grep "..." >&3 )
これはFD 1の標準出力を取得し(新しく作成された)FD 3を指します。直接実行すると、FD 3はどこにも行かないので動作しませんが、次のようにマージして利用できます。
( grep "..." >&3 ) 3>&1 1>/dev/null
括弧内のコマンドはFD3に出力されます。後続のリダイレクトは、1)FD 3(現在実際にコンテンツがある)をFD 1に指定し、次に2)FD 1を再割り当てします(これは効果がありません)。最終的な結果は、grep "..."
何の乱れもなく正確にすべき場所から標準出力に戻すことができるということです。
このリダイレクトが実際に行うことは次のとおりです。それはまるで
cmd 3>&1 1>&2 2>&3 3>&- | foo
FD 3 を一時保存ポイントとして使用し、FD 1 と 2 を交換します。時にはシェルスクリプトトリックにも使用されます。POSIX shでの偽のプロセスの交換( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
。それ以外の場合、コマンド自体が非標準のファイル記述子を数値として使用することはほとんどありません(もちろん、多くのコマンドはファイル自体を開いてインポートします)。