18

stdout に出力しながら両方がファイルに書き込まれるように stdout+stderr をリダイレクトするのは簡単です。

cmd 2>&1 | tee output_file

しかし、今ではcmdからのstdout/stderrの両方がstdoutに来ています。stdout+stderr を同じファイルに書き込みたいのですが (したがって、cmd がシングル スレッドであると仮定して順序が保持されます)、次のように個別にリダイレクトすることもできます。

some_magic_tee_variant combined_output cmd > >(command-expecting-stdout) 2> >(command-expecting-stderr)

したがって、結合された出力には順序が保持された両方が含まれますが、command-expecting-stdout は stdout のみを取得し、command-expecting-stderr は stderr のみを取得します。基本的に、stdout と stderr を個別にリダイレクトしてパイプ処理できるようにしながら、stdout+stderr をログに記録したいと考えています。ティーアプローチの問題は、それらを一緒にグロブすることです。bash/zsh でこれを行う方法はありますか?

4

5 に答える 5

2

私が理解していることから、これはあなたが探しているものです。最初に、stdout と stderr に書き込む小さなスクリプトを作成しました。次のようになります。

$ cat foo.sh 
#!/bin/bash

echo foo 1>&2
echo bar

次に、次のように実行しました。

$ ./foo.sh 2> >(tee stderr | tee -a combined) 1> >(tee stdout | tee -a combined)
foo
bar

私の結果は次のbashようになります。

$ cat stderr
foo
$ cat stdout 
bar
$ cat combined 
foo
bar

が他のコンテンツteeを上書きしないように -a フラグが必要であることに注意してください。tee

于 2012-09-20T17:30:22.127 に答える
1

これが私がそれを行う方法です:

exec 3>log ; example_command 2>&1 1>&3 | tee -a log ; exec 3>&-

実施例

bash$ exec 3>log ; { echo stdout ; echo stderr >&2 ; } 2>&1 1>&3 | \
      tee -a log ; exec 3>&-
stderr
bash$ cat log
stdout
stderr

仕組みは次のとおりです。

exec 3>log追って通知があるまで、ファイル記述子 3 を log というファイルにリダイレクトするように設定します。

example_commandこれを実用的な例にするために、 を使用し{ echo stdout ; echo stderr >&2 ; }ました。ls /tmp doesnotexistまたは、代わりに出力を提供するために使用できます。

|bash が最初に実行するため、この時点でパイプにジャンプする必要があります。パイプはパイプをセットアップし、ファイル記述子 1 をこのパイプにリダイレクトします。これで、STDOUT がパイプに入ります。

ここで、左から右への解釈で次の場所に戻ることができます。2>&1これは、プログラムからのエラーは、STDOUT が現在指している場所、つまり、セットアップしたばかりのパイプに行くことを示しています。

1>&3これは、STDOUT がファイル記述子 3 にリダイレクトされることを意味します。ファイル記述子 3 は、以前にファイルに出力するように設定されていましたlog。そのため、コマンドからの STDOUT は、端末の STDOUT ではなく、ログ ファイルに入れられます。

tee -a logパイプからの入力を受け取り (これはコマンドからのエラーであることに注意してください)、それを STDOUT に出力し、ファイルに追加しlogます。

exec 3>&-ファイル記述子を閉じます 3.

于 2014-04-15T10:57:51.873 に答える
1

確かに秩序は保たれます。以下は、標準出力とエラーを生成された順序でログファイルにキャプチャし、任意の端末画面に標準エラーのみを表示する例です。ニーズに合わせて微調整します。

1.2つのウィンドウ(シェル)を開く

2.いくつかのテストファイルを作成します

touch /tmp/foo /tmp/foo1 /tmp/foo2

3.window1:

mkfifo /tmp/fifo
</tmp/fifo cat - >/tmp/logfile

4.次に、window2 で:

(ls -l /tmp/foo /tmp/nofile /tmp/foo1 /tmp/nofile /tmp/nofile; echo successful test; ls /tmp/nofile1111) 2>&1 1>/tmp/fifo | tee /tmp/fifo 1>/dev/pts/1

/dev/pts/1 は、任意の端末表示にできます。サブシェルはいくつかの「ls」コマンドと「echo」コマンドを順番に実行し、一部は成功 (stdout を提供) し、一部は失敗 (stderr を提供) して、出力とエラー メッセージの混合ストリームを生成します。ログファイル。

于 2013-08-02T20:10:54.957 に答える
1
{ { cmd | tee out >&3; } 2>&1 | tee err >&2; } 3>&1

または、衒学的に言うと:

{ { cmd 3>&- | tee out >&3 2> /dev/null; } 2>&1 | tee err >&2 3>&- 2> /dev/null; } 3>&1

秩序を維持しようとしても無駄であることに注意してください。基本的に無理です。唯一の解決策は、「cmd」を変更するか、いくつかを使用するかLD_PRELOADgdbハックすることです。

于 2012-10-14T20:52:02.843 に答える
1

Victor Sergienkoのコメントは私にとってはうまくいきました。その前に exec を追加すると、スクリプト全体でこれが機能します(個々のコマンドの後に配置する必要はありません)

exec 2> >(tee -a output_file >&2) 1> >(tee -a output_file)

于 2015-04-07T21:37:31.977 に答える