編集:私は脱線し、尋ねられたものとは異なる質問に答えてしまったようです 本当の質問に対する答えは、ポール・トンブリンの答えの一番下にあります。(何らかの理由でstdoutとstderrを別々にリダイレクトするようにソリューションを拡張したい場合は、ここで説明する手法を使用できます。)
stdoutとstderrの違いを維持する答えを求めていました。残念ながら、その区別を維持するためにこれまでに与えられたすべての回答は、競合が発生しやすくなります。私がコメントで指摘したように、プログラムは不完全な入力を参照するリスクがあります。
私はようやく、その区別を維持し、人種が発生しにくく、ひどく面倒でもない答えを見つけたと思います。
最初の構成要素:stdoutとstderrを交換するには:
my_command 3>&1 1>&2 2>&3-
2番目の構成要素:stderrのみをフィルタリング(たとえば、tシャツ)したい場合は、stdout&stderrを交換し、フィルタリングしてから、元に戻すことで実現できます。
{ my_command 3>&1 1>&2 2>&3- | stderr_filter;} 3>&1 1>&2 2>&3-
あとは簡単です。最初にstdoutフィルターを追加できます。
{ { my_command | stdout_filter;} 3>&1 1>&2 2>&3- | stderr_filter;} 3>&1 1>&2 2>&3-
または最後に:
{ my_command 3>&1 1>&2 2>&3- | stderr_filter;} 3>&1 1>&2 2>&3- | stdout_filter
上記のコマンドが両方とも機能することを納得させるために、私は次のコマンドを使用しました。
alias my_command='{ echo "to stdout"; echo "to stderr" >&2;}'
alias stdout_filter='{ sleep 1; sed -u "s/^/teed stdout: /" | tee stdout.txt;}'
alias stderr_filter='{ sleep 2; sed -u "s/^/teed stderr: /" | tee stderr.txt;}'
出力は次のとおりです。
...(1 second pause)...
teed stdout: to stdout
...(another 1 second pause)...
teed stderr: to stderr
teed stderr: to stderr
期待どおり、プロンプトが「」の直後に戻ってきます。
zshに関する脚注:
上記の解決策はbashで機能します(おそらく他のいくつかのシェル、私にはわかりません)が、zshでは機能しません。zshで失敗する理由は2つあります。
- 構文
2>&3-
はzshによって理解されません。次のように書き換える必要があります2>&3 3>&-
- zshでは(他のシェルとは異なり)、すでに開いているファイル記述子をリダイレクトすると、場合によっては(それがどのように決定するのか完全に理解できません)、代わりに組み込みのTシャツのような動作をします。これを回避するには、リダイレクトする前に各fdを閉じる必要があります。
したがって、たとえば、私の2番目のソリューションは、zshのように書き直す必要があります{my_command 3>&1 1>&- 1>&2 2>&- 2>&3 3>&- | stderr_filter;} 3>&1 1>&- 1>&2 2>&- 2>&3 3>&- | stdout_filter
(これはbashでも機能しますが、非常に冗長です)。
一方、zshの不可解な組み込み暗黙的ティーイングを利用して、ティーをまったく実行しないzshのはるかに短いソリューションを取得できます。
my_command >&1 >stdout.txt 2>&2 2>stderr.txt
(私は私がことがわかったドキュメントから推測しなかったであろう>&1
と2>&2
、トリガーのzshの暗黙のティーイングという事であり、私は試行錯誤によってそのアウトを発見しました)