bash:将标准输出和标准错误重定向(并附加)到文件和终端并获得正确的退出状态

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2413166/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:01:22  来源:igfitidea点击:

bash: redirect (and append) stdout and stderr to file and terminal and get proper exit status

bashstdoutstderrtee

提问by rouble

To redirect (and append) stdout and stderr to a file, while also displaying it on the terminal, I do this:

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

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

However, is there another way to do this such that I get an accurate value for the exit status?

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

That is, if I test $?, I want to see the exit status of command, not the exit status of tee.

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

I know that I can use ${PIPESTATUS[0]}here instead of $?, but I am looking for another solution that would not involve having to check PIPESTATUS.

我知道我可以使用${PIPESTATUS[0]}here 而不是$?,但我正在寻找另一种无需检查的解决方案PIPESTATUS

采纳答案by Martin

Perhaps you could put the exit value from PIPESTATUS into $?

也许您可以将 PIPESTATUS 的退出值放入 $?

command 2>&1 | tee -a file.txt ; ( exit ${PIPESTATUS} )

回答by vladr

Another possibility, with some bashflavours, is to turn on the pipefailoption:

另一种可能,有一些bash风味,是打开pipefail选项:

pipefail

If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.

管道故障

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

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

This having been said, the only way of achieving PIPESTATUSfunctionality portably (e.g. so it'd also work with POSIX sh) is a bit convoluted, i.e. it requires a temp fileto propagate a pipe exit status back to the parent shell process:

话虽如此,实现PIPESTATUS可移植功能的唯一方法(例如,它也适用于 POSIX sh)有点复杂,即它需要一个临时文件来将管道退出状态传播回父 shell 进程:

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

or, encapsulating for reuse:

或者,封装以供重用:

log2file() {
  LOGFILE="" ; 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 $?"

or, more generically perhaps:

或者,更笼统地说,也许是:

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

get_pipe_status() {
  STATUS_ID="" ; 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

回答by johnraff

Use process substitution:

使用进程替换:

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

tee runs in a subshell so $? holds the exit status of command.

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

回答by jpalecek

There is an arcane POSIX way of doing this:

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

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

It will set the variable Rto the return value of command1, and pipe output of command1to command2, whose output is redirected to the output of parent shell.

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