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に複製されます)
- &3を閉じる(&-は3に複製されます)
3>&2 2>&1 1>&3-
ます。
$ 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
元STDERRへのSTDOUTバック。
exec 2> >(while .. read .. echo)
systemdサービスとして実行されているスクリプトでこれを行うことでやけどを負いました。journaldはサービスのfd2をキャプチャし、「<N>」プレフィックスからログレベルを推測します。<2>
出力行の先頭に追加すると、ジャーナルレコードに割り当てられたERRORレベルが取得されます。しかし、systemdは、最後の最も重要なメッセージをログに記録する前に、メイングループの終了時にプロセスグループ全体を迅速に強制終了することがありました。
プロセス置換を素朴に使用すると、以下とは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
$
コマンドプロンプトとして使用する人もいます。次に、次のようなシェルの例を作成することがよくあります$ cat /var/log/syslog | fgrep ...
。ただし、この行は$
。のためにコピーして貼り付けることはできません。:;
プロンプトのように見えますが、基本的にはシェルの操作なしです。そのため、行全体を安全に選択して貼り付けることができます。
$ 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を元の値に再度スワップしない限り、コマンドを他のコマンドにパイプできないことです。
POSIXsh
での前方配管を可能にするために(そしてFD 3が使用されていないと仮定して)それは複雑になります:
(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1
したがって、これの仮定と厄介な構文を考えると、上記のTL; DRに示され、ここで説明されているより単純なbash
/zsh
構文を使用する方が良いでしょう。
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.
#ありがとう、SC
これはあなたが望むものかもしれません。そうでない場合は、ABSGの他の部分があなたを助けることができるはずです、それは素晴らしいです。
名前付きパイプを見てください:
$ mkfifo err
$ cmd1 2>err |cat - err |cmd2
cat - err
stdoutとstderrの散在を壊しませんか?