web-dev-qa-db-ja.com

STDERRのみをフィルターにパイプする

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

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

のではなく

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

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. close&3(&-は3になります)
57
Paul Rubel

プロセス置換の単純な使用は、stderrとは別にstdoutのフィルタリングを許可するようです:

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

stderrstderrに、stdoutにはstdoutに出てくることに注意してください。これらは別のサブシェルですべてをラップし、ファイルoおよびe

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

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)

>&2filterのSTDOUTを元のSTDERRにリダイレクトします。

12
Tom Hale

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を元の値に再度スワップしない限り、コマンドを他のコマンドにパイプできないことです。

POSIX shで前方へのパイピングを許可するには、(そしてまだFD 3が使用していないと仮定して)それは 複雑になります

(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1

したがって、これの仮定と厄介な構文を考えると、上記のTL; DRに示されている here で説明されている、より単純なbash/zsh構文を使用する方が良いでしょう。

9
Tom Hale

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

8
Pecunifex

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

5
signine

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

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