私は機能的に同じと思われる2つの構造の違いを引き起こす原因を理解しようとしています。
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') | sed 's/^/stdout: /'
stdout: stderr: foo
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(sed 's/^/stdout: /')
stderr: foo
編集:user1133275を正しく理解した場合、彼は標準出力に出力しないとサブシェルが>(sed 's/^/stdout: /')
実行されない( echo foo >&2 )
ことを提案しました。しかし、これは次のことを意味します。
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(echo baz)
baz
stderr: foo
表示しないでくださいbaz
。
stdout:
編集2:おそらく興味深いことに、sedはパイピング中に空の入力に対して出力しません。
$ sed 's/^/stdout: /' < /dev/null
$ printf "" | sed 's/^/stdout: /'
$
ベストアンサー1
最初のコマンド、
( echo foo >&2 ) 2> >(sed 's/^/stderr: /') | sed 's/^/stdout: /'
単純化された形式(生成されたデータを保存するために一時ファイルを使用echo
):
{ echo foo 2>file >&2; sed 's/^/stderr: /' file; } | sed 's/^/stdout: /'
つまり、最初のものはsed
標準エラーの結果の内容を読み取り、echo
それを標準出力に書き込み、2番目のものはsed
それを読み取って修正します。
2番目のコマンドは
( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(sed 's/^/stdout: /')
単純化された形で、
echo foo 2>file >&2; sed 's/^/stderr: /' file; sed 's/^/stdout: /' </dev/null
ここでsed
、stderrを取得することは出力を生成しますが、stderr(何もなし)を取得する他はsed
出力を生成しません(入力が得られず、データが挿入または追加されないため)。
他の表現として:
最初のコマンド:
( echo foo >&2 ) 2>file
sed 's/^/stderr: /' file | sed 's/^/stdout: /'
2番目のコマンド:
( echo foo >&2 ) 2>file >otherfile
sed 's/^/stderr: /' file
sed 's/^/stdout: /' otherfile
つまり、sed
2つのコマンドのうち2番目のコマンドは何も読みません。特に、最初のコマンドと同様に、最初のコマンドの出力を読み取ることはありませんsed
。
非常に単純化された表記法を使用すると、最初のコマンドは次のようになります。
utility-writing-to-stderr 2> >(something1) | something2
これはsomething1
標準出力に書き込まれますsomething2
。
2番目のコマンドは同じ表記法を使用します。
utility-writing-to-stderr 2> >(something1) >(something2)
つまり、互いに連結されていsomething1
なくても何らかの方法で生成される内容を読み取ることができません。さらに、標準出力ストリームでは何も生成されないため、標準入力から何も読み取れません。something2
something2
something1
utility-writing-to-stderr
something2