web-dev-qa-db-ja.com

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

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

$ 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の内容は1行ずつリアルタイムで表示されます。つまり、バッファリングは行われません。
  • 個別のスクリプトファイルを使用できます。
  • 魔法が必要かもしれません。
19
TWiStErRob
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を作成し、teeにその出力を同じファイルに書き込むことによって機能します。

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

パイプはバッファであるため、出力が正しい順序でファイルに表示される保証はありません。アプリケーションが両方のファイル記述子(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メソッドよりも高速または低速になる場合があります。ヒューズが最大速度のソリューションになります。
13
Hauke Laging