stdoutとstderrをファイルにリダイレクトし、stderrをコンソールに表示する方法は?


18

ファイルにリダイレクトする方法と、teeを使用する方法を知っています。基本的なレベルで。そう

$ alias outanderr='bash -c "echo stdout >&1; echo stderr >&2"'
# A fake "application" displaying both output and error messages.

$ outanderr 1>file      # redirect stdout to a file, display stderr
stderr

$ outanderr 2>file      # redirect stderr to a file, display stdout
stdout

$ outanderr 1>file 2>&1 # redirect both to a file, display nothing

$ outanderr | tee file; echo "-- file contents --" && cat file
# redirect stdout to a file, display both (note: order is messed up)
stderr
stdout
-- file contents --
stdout

$ outanderr 2>&1 | tee file; echo "-- file contents --" && cat file
# redirect both to a file, display both
stdout
stderr
-- file contents --
stdout
stderr

問題は、以下の出力を得るために疑問符の代わりに何を書くかです。

$ outanderr ???; echo "-- file contents --" && cat file
# redirect both to a file, display stderr
stderr
-- file contents --
stdout
stderr

内容:

  • bashを想定しています。
  • 順序はファイルに保持する必要があります。
  • stderrの内容はリアルタイムで行ごとに表示されます。つまり、バッファリングは行われません。
  • 個別のスクリプトファイルを使用できます。
  • 魔法が必要な場合があります。

outanderrプログラムをどの程度管理していますか?
ケビン

1
@Kevin質問はそれよりも一般的だと思います。これは、outanderrstdoutとstderrに1行を出力する単なるエイリアスです。(可能であれば)アイデアは、プログラムを変更せずに、どのプログラムでも機能する汎用ソリューションを構築することです。
lgeorget

@lgeorget私はそれを理解していますが、一般的なソリューションのすべての制約を厳密に満たすことができるとは思わないので、特定の制約を取得できるかどうかを見ていました。
ケビン

@Igeorgetは正しい。
TWiStErRob

回答:


12
2>&1 >>outputfile | tee --append outputfile

簡単なテストの場合:

echo -n >outputfile; bash -c "echo stdout >&1; echo stderr >&2" 2>&1 >>outputfile |
  tee --append outputfile; echo "outputfile:"; cat outputfile

編集1:

これは、stdout(のみ)をファイルに書き込み、パイプを通過するようにsterr stdoutを作成し、Tが同じファイルに出力を書き込むことで機能します。

両方の書き込みは(>>ではなく>)追加モードで実行する必要があります。そうしないと、両方が互いの出力を上書きします。

パイプはバッファーであるため、出力が正しい順序でファイルに表示される保証はありません。アプリケーションが両方のファイル記述子(2つのパイプ)に接続されていても、これは変わりません。順序を保証するには、両方の出力が同じチャネルを通過し、それぞれマークされる必要があります。または、いくつかの本当に派手なものが必要になります。

  1. stdoutとstderrの両方がファイル(同じファイルではない!)にリダイレクトされ、両方のファイルがFUSEボリュームにある場合、FUSEモジュールは各書き込みにタイムスタンプを付けて、2番目のアプリケーションがデータを正しくソートして結合できるようにしました実際の出力ファイル用。または、データをマークせずに、モジュールに結合出力ファイルを作成させます。ほとんどの場合、これを行うFUSEモジュールはまだありません...
  2. stdoutとstderrの両方をに向けることができます/dev/null。アプリケーションを実行すると、アプリケーションの出力が分離されstrace -f -s 32000 -e trace=writeます。その場合、エスケープを元に戻す必要があります。言うまでもなく、アプリケーションはトレースされても高速に実行されません。
  3. 既存のシンプルなFUSEモジュールを使用し、アプリケーションの代わりにモジュールをトレースすることで、同じことができるかもしれません。モジュールはおそらくアプリケーションよりもはるかに少ないシステムコールを持っているため、これはアプリケーションをトレースするよりも高速かもしれません。
  4. アプリケーション自体を変更できる場合:アプリは各出力後に停止できますが(内部からのみ可能だと思います)、sシグナル(SIGUSR1またはSIGCONT)を受信した後にのみ続行できます。パイプから読み取るアプリケーションは、パイプとファイルの両方で新しいデータをチェックし、新しいデータごとに信号を送信する必要があります。アプリケーションの種類に応じて、これはstraceメソッドよりも高速または低速になる場合があります。FUSEは最高速度のソリューションです。

1
ああ。どうしていけないのか、まったく同じ答えを書いている最中に私を捕まえてください。
ケビン

2
NBこれには競合する状態があり、out / err行を交換する可能性がありますが、それを回避できるとは思いません。
ケビン

1
@Kevinそれは私たちの最高の出来事です、私は以前にそれに苦しみ、「誰かが書いていることを見せてください」機能を要求していました(しかし、それは複雑です)。競合状態は、パイプラインへの書き込み後にファイル(stdout)への書き込みが発生した場合にのみ発生するようです。
ハウケレイジング

との両方stdoutstderrに送信しませんteeか?OPの要件はそれtee stderrだけだと思います。
ジョセフR.

@JosephR。あなたはそれを試したことはありませんか?
ハウケレイジング
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.