質問

実行中のコマンドのSTDOUT / STDERRを捕捉し、処理コマンドと同じ終了ステータスで終了し、「ティー」の代替があります。次のように何かます:

eet -a some.log -- mycommand --foo --bar

「EET」は「ティーショット」する:)架空の代替である場合 - このようなコマンドをハックするのは難しいことではないはずです(-a手段を追加するには、キャプチャコマンドを分離)が、多分それは既に存在していると私はそれに気づいていない?

感謝します。

役に立ちましたか?

解決

ここでeetです。すべてのバッシュで動作します私は2.05bから4.0に、上の私の手を得ることができます。

#!/bin/bash
tee_args=()
while [[ $# > 0 && $1 != -- ]]; do
    tee_args=("${tee_args[@]}" "$1")
    shift
done
shift
# now ${tee_args[*]} has the arguments before --,
# and $* has the arguments after --

# redirect standard out through a pipe to tee
exec | tee "${tee_args[@]}"

# do the *real* exec of the desired program
exec "$@"

pipefail$PIPESTATUSはいいですが、私は彼らが3.1またはその付近に導入されて思い出してください。)

他のヒント

これはbashので動作します:

(
  set -o pipefail
  mycommand --foo --bar | tee some.log
)

括弧は単に一つのコマンドにpipefailの効果を制限することがあります。

はbash(1)のmanページから:

pipefailオプションが有効になっていない限り、パイプラインのリターン・ステータスは、最後のコマンドの終了ステータスです。 pipefailが有効になっている場合は、すべてが正常に終了コマンドならば、パイプラインのリターン・ステータスは、最後の(右端の)非ゼロのステータスで終了し、コマンド、またはゼロの値です。

ここで興味深いソリューションのカップルにつまずい http://www.perlmonks.org/?node_id= 597613 のます。

1)$ PIPESTATUS変数はbashで利用可能があります:

   false | tee /dev/null
   [ $PIPESTATUS -eq 0 ] || exit $PIPESTATUS

2)そして、次のようにPerlで "EET" の最も簡単なプロトタイプが見えることがあります:

   open MAKE, "command 2>&1 |" or die;
   open (LOGFILE, ">>some.log") or die;
   while (<MAKE>) { print LOGFILE $_; print }
   close MAKE; # to get $?
   my $exit = $? >> 8;
   close LOGFILE;

ALL 1行でKornシェル、:

foo; RET_VAL=$?; if test ${RET_VAL} != 0;then echo $RET_VAL; echo Error occurred!>/tmp/out.err;exit 2;fi |tee >>/tmp/out.err ; if test ${RET_VAL} != 0;then exit $RET_VAL;fi

これは、私はあなたがあなたの「EET」を構築することができ、その上にベースとして使用するのに最適な、純粋な-ボーン・シェル溶液であることを考えるものです。

# You want to pipe command1 through command2:
exec 4>&1
exitstatus=`{ { command1; printf $? 1>&3; } | command2 1>&4; } 3>&1`
# $exitstatus now has command1's exit status.
それが行わだ後は、その後、printf関数を実行し、その標準出力にプリントのCommand1の終了コードし、実行し、標準出力にその定期的な出力を表示しますCommand1を(ファイルディスクリプタ1)が、そのstdoutが -

私は、これが最良の内側から説明されていると思います記述子3をファイルにリダイレクトされます。

のCommand1を実行している間、その標準出力は、(printf関数の出力は、決して私たちはパイプの読み取り何である、記述子3の代わりに、1ファイルにそれを送るので、それがCOMMAND2することができません)COMMAND2にパイプされています。それはまた、ファイルディスクリプタ1の外に留まるようにその後、我々は、記述子4を提出するコマンド2の出力をリダイレクトする - 私たちは少し後でのためのファイルディスクリプタ1自由たいので、私たちはファイルディスクリプタに戻すダウンファイルディスクリプタ3のprintfの出力をもたらすため、 1 - それはどのようなコマンド置換(バッククォート)ですので、キャプチャし、それを変数に置かれます何でしょう。

魔法の最終ビットは、最初のexec 4>&1私たちは別々のコマンドとしてやったということである - それは、外部シェルの標準出力のコピーとしてファイルディスクリプタ4を開きます。コマンド置換は、内部コマンドの観点から、標準的に書かれているものは何でもキャプチャします - しかし、コマンド2の出力は限りコマンド置換に関しては、ディスクリプタ4を提出しようとしているので、コマンド置換は、それをキャプチャしていない - しかし、それはコマンド置換の「アウト」を取得すると、それが効果的にまだスクリプトの全体的なファイル記述子1に起こっている。

exec 4>&1は、あなたが代入を使用している「外部」コマンドで開かれているコマンド置換、内部のファイル記述子への書き込みしようとすると、多くの一般的なシェルがそれを好きではないので、別のコマンドである必要があります。だから、これはそれを行うための最も簡単なポータブルな方法である。)

そのためcommand2のは、それをキャッチしていないのCommand1パイプがCOMMAND2し、その後、printf関数の出力は、コマンド2の上にジャンプします。

あなたは、コマンドの出力がお互いを飛び越すているかのように、以下の技術と、より遊び心の方法でそれを見ることができます、そしてそれは、変数で終わるように、2の出力がオーバーと時間だけで同じようにprintfのランドは置換によってキャプチャを取得するにはコマンド置換の飛び出しコマンド、およびコマンド2の出力は標準出力に書き込まれ、その陽気な方法に行きます、普通のパイプである。

変数の代入、コマンド置換、および化合物のコマンドは、すべてのそれらの内部コマンドのリターンコードを効果的に透明であるため、

また、私はそれを理解し、$?はまだそう、パイプ内の2番目のコマンドのリターンコードが含まれていますコマンド2の戻りステータスが出て伝播されるはずです。

の注意点は、それがCommand1をがある時点でファイルディスクリプタ4を使用するファイルディスクリプタ3または4、またはそのコマンド2以降のコマンドのいずれかを使用して終了する可能性があるということですので、より堅牢であることを、あなたはどうなります

exec 4>&1
exitstatus=`{ { command1 3>&-; printf $? 1>&3; } 4>&- | command2 1>&4; } 3>&1`
exec 4>&-

私は私の例では、化合物のコマンドを使用しますが、サブシェル(おそらくあまり効率的でもよいが、代わりにも動作する( ){ }を使用。)

コマンドは、それらを起動するプロセスからファイル記述子を継承するので、全体の2行目は、ファイルディスクリプタ4を継承し、3>&1続く複合コマンドは、ファイルディスクリプタ3を継承します。だから、4>&-は、内側の複合コマンドは、ファイルディスクリプタ4を継承しないことを確認します、と3>&-はファイルディスクリプタ3を継承することはありませんので、Command1が「クリーン」、より標準的な環境を取得します。あなたはまた、4>&-の隣のインナー3>&-を移動することもできますが、私は可能な限りその範囲を限定しない理由を理解しています。

私は物事が直接ファイルディスクリプタ3と4を使用する頻度わからない - 私はトンのほとんどを考えます彼の時間のプログラムは、使用していない・アット・モーメントファイルディスクリプタを返すシステムコールを使用しますが、時々コードが、私は(私はそれが開いているかどうかを確認するためにファイルディスクリプタをチェックするプログラムを想像することができると思い、直接記述子3をファイルに書き込み、それを使用してそれがある場合、またはそれは)ない場合はそれに応じて異なる動作を。だから、後者はおそらく念頭に置いておくと、汎用のケースのために使用することをお勧めします。

---この行の下に古いコンテンツを---

は歴史的な理由のために、ここで私の元には、ポータブルではないツーすべてのシェルでは答えます:

[EDIT]私の悪い、ファイルディスクリプタをいじるときbashが余分coddlingを必要とするため、これはbashのでは動作しませんが、私はすぐに私ができるようにこれを更新します。 【/ EDIT]

ピュアBourneシェル・ソリューション:

exitstatus=`{ 3>&- command1; } 1>&3; printf $?` 3>&1 | command2
# $exitstatus now has command1's exit status.

これは、あなたの「EET」を構築することができ、その上にベースです。いくつかのコマンドライン引数の解析とすべてのことに平手打ち、関連するオプションなどで「ティー」にコマンド2を回します。

次のように

非常に詳細な説明があります:

トップレベルで、文は2つのコマンドの単なるパイプであります:

commandA | command2

順番にcommandAは、ファイルディスクリプタ1(stdout)にファイルディスクリプタ3のリダイレクトを単一のコマンドに分解します:

commandB 3>&1
ファイルディスクリプタ3が開かれることはありませんならば、それは誤りだろう -

このシェルがcommandBは、ディスクリプタ3をファイルに何かを書くことを期待されることを意味します。また、command2の両方のファイルディスクリプタ1(標準出力)および3上のどんなcommandB出力を取得することを意味します。

順番にcommandBは、コマンド置換を使用して変数の代入です。

VAR_FOO=`commandC`

私たちは、変数の割り当ては、任意のファイル記述子には何も印刷されないことを知っている(とcommandCの標準出力は、置換のために捕獲された)ので、私たちは全体としてcommandBが標準出力に何も出力しないことを知っています。 command2のは、このようにだけcommandCは記述子3をファイルに書き込むかを確認します。

そしてcommandCは、第2のコマンドは、最初の終了ステータスを印刷する二つのコマンド、である

commandD ; printf $?

だから今で我々は最後のステップで変数の割り当てがcommandDの終了ステータスが含まれています知っています。

さて、commandDは記述子3ファイルにcommanのstdoutと、別の基本的なリダイレクトに分解する

commandE 1>&3

だから今、私たちはものは、ディスクリプタ3ファイルへの書き込みことを知っているので、最終的にCOMMAND2するには、commandEのstdoutです。

最後ます:

:commandEは「リダイレクト」の他のあまり一般的に見られるタイプのラップアラウンド、「複合コマンド」(あなたもここにサブシェルを使用することができますが、それは効率的ではありません)です
{ 3>&- command1; }

(私たちは最後にそれに戻って来るように3>&-は少しトリッキーです。)最後のコマンドと最後のブレースは、同じライン上にあるときに化合物のコマンドは、そのセミコロンは必須に、それがある理由です。だから我々は、化合物のコマンドは彼らの最後のコマンドの終了コードを返す知っており、彼らは他のすべてのようなファイルディスクリプタを継承するので、私たちは今、そのCommand1をの標準出力は、複合コマンドから流出知って、コマンド置換によって捕捉されるのを避けるために、ディスクリプタ3をファイルにリダイレクトします一方、コマンド置換は、それが行われた後のCommand1の終了ステータスをエコーのprintfの残りの標準出力をキャッチします。

そして今、トリッキーなビットのために:3>&-は「近いファイルディスクリプタ3」と言います。あなたは「あなたはそれにCommand1をの出力をリダイレクトするとき、なぜあなたはそれを閉じていますか?」、と思うかもしれあなたは慎重に見ればまあ、あなたはリダイレクトが全体の複合コマンドに影響を与える一方で近い効果が唯一、特に(中括弧内)複合コマンド内COMMAND1ていることがわかります。

時間によって複合コマンド実行の個々のコマンドは、シェルがそうCommand1を、3のプロセスがファイル記述子を継承したファイルディスクリプタをオープンし、デフォルトでは、ファイル記述子3オープンで実行されますし、を指す:

だからここに何が起こるかでありますあまりにも同じ場所。時折、プログラム、実際にこれは悪いです特別なものを意味し、特定のファイルディスクリプタを期待する - ファイルディスクリプタ3開いて立ち上げたとき、彼らは動作が異なる場合があります。最も堅牢なソリューションはただのCommand1のためだけ近いファイルディスクリプタ3(またはどちらかお使いの数)であり、それはファイルディスクリプタ3が開かれなかったかのように通ります。

それが実行されます
{ mycommand --foo --bar 2>&1; ret=$?; } | tee -a some.log; (exit $ret)
#!/bin/sh
logfile="$1"
shift
exec 2>&1
exec "$@" | tee "$logfile"

うまくいけば、これはあなたのために働くます。

やあ、

はbashやzshのを想定すると、

my_command >>my_log 2>&1

N.B。 STDOUTへのSTDERRのリダイレクトと重複の順序は重要です!

編集のおっと。あなたにも、画面上の出力を見てみたかった実現しませんでした。これはもちろん、ファイルmy_logにすべての出力を指示します。

HTH

歓声、

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top