35

stdout と stderr をファイルにリダイレクト (および追加) し、端末にも表示するには、次のようにします。

command 2>&1 | tee -a file.txt

ただし、終了ステータスの正確な値を取得するためにこれを行う別の方法はありますか?

つまり、 をテストする場合、 の終了ステータスではなく、 の終了$?ステータスを確認したいのです。commandtee

${PIPESTATUS[0]}の代わりにここで使用できることはわかっています$?が、チェックする必要のない別の解決策を探していPIPESTATUSます。

4

4 に答える 4

30

おそらく、PIPESTATUSからの終了値をに入れることができます$?

command 2>&1 | tee -a file.txt ; ( exit ${PIPESTATUS} )
于 2010-03-09T23:06:47.650 に答える
6

いくつかのフレーバーがある別の可能性は、オプションbashをオンにすることです:pipefail

pipefail

設定されている場合、パイプラインの戻り値は、ゼロ以外のステータスで終了する最後の(右端の)コマンドの値です。パイプライン内のすべてのコマンドが正常に終了した場合はゼロになります。このオプションはデフォルトで無効になっています。

set -o pipefail
...
command 2>&1 | tee -a file.txt || echo "Command (or tee?) failed with status $?"

とはいえ、機能を移植可能に実現する唯一の方法PIPESTATUS(たとえば、POSIXでも機能する)は少し複雑です。つまり、パイプの終了ステータスを親シェルプロセスに伝播するために一時ファイルshが必要です。

{ command 2>&1 ; echo $? >"/tmp/~pipestatus.$$" ; } | tee -a file.txt
if [ "`cat \"/tmp/~pipestatus.$$\"`" -ne 0 ] ; then
  ...
fi

または、再利用のためにカプセル化する:

log2file() {
  LOGFILE="$1" ; shift
  { "$@" 2>&1 ; echo $? >"/tmp/~pipestatus.$$" ; } | tee -a "$LOGFILE"
  MYPIPESTATUS="`cat \"/tmp/~pipestatus.$$\"`"
  rm -f "/tmp/~pipestatus.$$"
  return $MYPIPESTATUS
}

log2file file.txt command param1 "param 2" || echo "Command failed with status $?"

または、より一般的にはおそらく:

save_pipe_status() {
  STATUS_ID="$1" ; shift
  "$@"
  echo $? >"/tmp/~pipestatus.$$.$STATUS_ID"
}

get_pipe_status() {
  STATUS_ID="$1" ; shift
  return `cat "/tmp/~pipestatus.$$.$STATUS_ID"`
}

save_pipe_status my_command_id ./command param1 "param 2" | tee -a file.txt
get_pipe_status my_command_id || echo "Command failed with status $?"

...

rm -f "/tmp/~pipestatus.$$."* # do this in a trap handler, too, to be really clean
于 2010-03-10T03:35:54.953 に答える
4

プロセス置換を使用します。

command > >( tee -a "$logfile" ) 2>&1

ティーはサブシェルで実行されるので、$? commandの終了ステータスを保持します。

于 2015-06-02T08:01:56.733 に答える