Bashで、STDOUTと統合する前にSTDERRをフィルタにパイプする方法はありますか?つまり、私は欲しい
STDOUT ────────────────┐
├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘
のではなく
STDOUT ────┐
├────[ filter ]───> terminal/file/whatever
STDERR ────┘
bashでファイル記述子を交換する方法 をモデルにした例を次に示します。 a.outの出力は次のようになりますが、 'STDXXX:'プレフィックスは付きません。
STDERR: stderr output
STDOUT: more regular
./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
more regular
stdErr output
上記のリンクから引用:
- 最初にstdoutを&3として保存します(&1は3にコピーされます)
- 次にstdoutをstderrに送信します(&2は1になります)
- Stderrを&3(stdout)に送信します(&3は2になります)
- close&3(&-は3になります)
プロセス置換の単純な使用は、stderr
とは別にstdout
のフィルタリングを許可するようです:
:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err
stderr
はstderr
に、stdout
にはstdout
に出てくることに注意してください。これらは別のサブシェルですべてをラップし、ファイルo
およびe
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e
$ cmd 2> >(stderr-filter >&2)
例:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
これはbashとzshの両方で機能します。 Bashは最近ほとんどどこにでもありますが、POSIX sh
の(本当に危険な)ソリューションが本当に必要な場合は、 こちらを参照 です。
これを行う最も簡単な方法は、 プロセス置換 を介してSTDERRをリダイレクトすることです。
プロセス置換により、ファイル名を使用してプロセスの入力または出力を参照できます。の形をとる
>(list)
プロセスリストは非同期で実行され、その入力または出力はファイル名として表示されます。
したがって、プロセス置換で得られるのはファイル名です。
あなたができるように:
$ cmd 2> filename
できるよ
$ cmd 2> >(filter >&2)
>&2
のfilter
のSTDOUTを元のSTDERRにリダイレクトします。
$ cmd 2> >(stderr-filter >&2)
例:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
StackExchangeネットワークに関する多くの回答の形式は次のとおりです。
cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
これには、ファイル記述子3が他の何かに使用されていないという前提が組み込まれています。
代わりに、名前付きファイル記述子を使用し、{ba,z}sh
は、次に利用可能なファイル記述子> = 10を割り当てます。
cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'
名前付きファイル記述子はPOSIX sh
ではサポートされていないことに注意してください。
上記のもう1つの問題は、STDOUTとSTDERRを元の値に再度スワップしない限り、コマンドを他のコマンドにパイプできないことです。
POSIX sh
で前方へのパイピングを許可するには、(そしてまだFD 3が使用していないと仮定して)それは 複雑になります :
(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1
したがって、これの仮定と厄介な構文を考えると、上記のTL; DRに示されている here で説明されている、より単純なbash
/zsh
構文を使用する方が良いでしょう。
Bashプロセス置換の使用は、元の意図をほとんど逐語的に反映しているため、覚えやすく使用しやすいと感じています。例えば:
$ cat ./p
echo stdout
echo stderr >&2
$ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/'
sTdout
STderr
最初のsedコマンドをstderrのみのフィルターとして使用し、2番目のsedコマンドを使用して、結合された出力を変更します。
コマンドを正しく解析するには、2>の後の空白が必須であることに注意してください。
Advanced Bash Scripting Guideの このページ の最後の部分は、「stderrのみをパイプにリダイレクトする」です。
#stderrのみをパイプにリダイレクトします。
exec 3>&1 # Save current "value" of stdout. ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls'). # ^^^^ ^^^^ exec 3>&- # Now close it for the remainder of the script.
#ありがとう、S.C。
これはあなたが望むものかもしれません。そうでなければ、ABSGの他の部分があなたを助けることができるはずです、それは素晴らしいです。
名前付きパイプを見てください。
$ mkfifo err
$ cmd1 2>err |cat - err |cmd2