STDERRのみをフィルターに通します


82

STDOUTと統合する前に、フィルターを介してSTDERRをパイプする方法はありますか?つまり、私は欲しい

STDOUT ────────────────┐
                       ├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘

のではなく

STDOUT ────┐
           ├────[ filter ]───> terminal/file/whatever
STDERR ────┘

回答:


64

これは、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

上記のリンクからの引用:

  1. 最初にstdoutを&3として保存します(&1は3に複製されます)
  2. 次に、stdoutをstderrに送信します(&2は1に複製されます)
  3. stderrを&3(stdout)に送信します(&3は2に複製されます)
  4. &3を閉じる(&-は3に複製されます)

1
それは私にはうまくいきません。最後に、で動作させ3>&2 2>&1 1>&3-ます。
aleung

3
注意:これは、FD 3が使用されていないことを前提としており、ファイル記述子1と2のスワッピングを元に戻さないため、これをさらに別のコマンドにパイプすることはできません。詳細と回避策については、この回答を参照してください。{ba、z} shのよりクリーンな構文については、この回答を参照してください。
トム・ヘイル

25

TL; DR:

$ 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バック。


1
この答えに沿った警告があります。bashは置換されたプロセスが完了するのを待ちませんが、FDが1と2を交換するためにジャグリングします。これは重要かもしれません。exec 2> >(while .. read .. echo)systemdサービスとして実行されているスクリプトでこれを行うことでやけどを負いました。journaldはサービスのfd2をキャプチャし、「<N>」プレフィックスからログレベルを推測します。<2> 出力行の先頭に追加すると、ジャーナルレコードに割り当てられたERRORレベルが取得されます。しかし、systemdは、最後の最も重要なメッセージをログに記録する前に、メイングループの終了時にプロセスグループ全体を迅速に強制終了することがありました。
KKM

素敵なシンプルなソリューション。警告:これをcronジョブの一部として使用する場合は注意が必要です。プロセス置換は、cronで使用される一部のシェルでは使用できません。
クインコメンダント

24

プロセス置換を素朴に使用すると、以下とはstderr別にフィルタリングできるようですstdout

:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err

stderrに出てくるstderrstdoutstdout、我々は別のサブシェルで全体を包むとファイルにリダイレクトすることで見ることができ、oかつe

( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e

なぜ :; 最初に?私はマジックラインを使わずに試しましたが、違いはないようです。
Koshmaar 2016

1
$コマンドプロンプトとして使用する人もいます。次に、次のようなシェルの例を作成することがよくあります$ cat /var/log/syslog | fgrep ...。ただし、この行は$。のためにコピーして貼り付けることはできません。:;プロンプトのように見えますが、基本的にはシェルの操作なしです。そのため、行全体を安全に選択して貼り付けることができます。
solidsnack 2016

23
わかりましたが、:;を省略できます。そして、その行もコピーして貼り付けることができます:)私にとって:; プロンプトのようには見えません。例を明確にする(コマンドを出力から分離する)のではなく、混乱を招きました。私はあなたの見解を理解しているので、構文/規則については説明しません。
Koshmaar 2016

15

TL; DR:(bashおよびzsh)

$ 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構文を使用する方が良いでしょう。


8

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>の後の空白が必須であることに注意してください。


5

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の他の部分があなたを助けることができるはずです、それは素晴らしいです。


違いを明確に示すことなく、文書、処方箋、意見が混在しているため、ABSGを参照として推奨することはやや躊躇しています。リンク先のセクションは問題ないように見えますが、一部のセクションにも疑わしいコンテンツが含まれています。
トリプリー2017年

3

名前付きパイプを見てください:

$ mkfifo err
$ cmd1 2>err |cat - err |cmd2

cat - errstdoutとstderrの散在を壊しませんか?
Martin DeMello 2010

@ Martin-状況によります。cmd1、cat、またはcmd2が出力をバッファリングする場合、出力の順序が狂っている可能性があります。
暴徒2010
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.