35

要将 stdout 和 stderr 重定向(并附加)到文件,同时在终端上显示它,我这样做:

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

但是,是否有另一种方法可以让我获得退出状态的准确值?

也就是说,如果我测试$?,我想查看 的退出状态command,而不是 的退出状态tee

我知道我可以${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选项:

管道故障

如果设置,则管道的返回值是以非零状态退出的最后一个(最右边)命令的值,如果管道中的所有命令成功退出,则返回零。默认情况下禁用此选项。

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

话虽如此,实现PIPESTATUS可移植功能的唯一方法(例如,它也可以与 POSIX 一起使用sh)有点令人费解,即它需要一个临时文件将管道退出状态传播回父 shell 进程:

{ 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

有一种神秘的 POSIX 方法可以做到这一点:

exec 4>&1; R=$({ { command1; echo $? >&3 ; } | { command2 >&4; } } 3>&1); exec 4>&-

它将变量设置R为 的返回值command1,并通过管道输出command1to command2,其输出被重定向到父 shell 的输出。

于 2010-03-10T23:25:57.230 回答
4

使用进程替换:

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

tee 在子shell 中运行,所以 $? 保持command的退出状态。

于 2015-06-02T08:01:56.733 回答