パイプラインは | で区切られたコマンドのリストです。指定したリダイレクトは構成コマンド (単純または複合) に適用されますが、パイプライン全体には適用されません。各パイプは、コマンドに関連付けられたリダイレクトが評価される前に、暗黙的に各サブシェルにリダイレクトを適用することにより、1 つのコマンドの stdout を次の stdin にチェーンします。
cmd 2>&1 | less
最初のサブシェルの最初の stdout は、less
読み取り元のパイプにリダイレクトされます。次に、2>&1
最初のコマンドにリダイレクトが適用されます。stdout は既にパイプを指しているため、stderr を stdout にリダイレクトすると機能します。
cmd | less 2>&1
ここで、リダイレクトは に適用されless
ます。Less の stdout と stderr はどちらも端末を指していると思われるため2>&1
、この場合は効果がありません。
リダイレクトをパイプライン全体に適用したり、パイプラインの一部として複数のコマンドをグループ化したり、パイプラインをネストしたりする場合は、コマンド グループ (またはその他の複合コマンド) を使用します。
{ { cmd1 >&3; cmd2; } 2>&1 | cmd3; } 3>&2
典型的な例かもしれません。最終結果は次のとおりです。 cmd1
andcmd2
の stderr -> cmd3
; cmd2
の標準出力 -> cmd3
; およびの stderr、およびcmd1
のstdout -> 端末。cmd3
cmd3
Bash 固有の|&
パイプを使用すると、パイプラインの stdout リダイレクトはそれぞれ最初に発生しますが、stderr リダイレクトは実際には最後に発生するため、事態はさらに奇妙になります。たとえば、次のようになります。
f() { echo out; echo err >&2; }; f >/dev/null |& cat
ここで、直感に反して、すべての出力が非表示になります。の最初の stdout がf
パイプに移動し、次の stdout がf
にリダイレクトされ/dev/null
、最後に stderr が stdout (/dev/null
静止) にリダイレクトされます。
|&
Bashでは絶対に使用しないことをお勧めします。ここではデモ用に使用しています。