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
bash: redirect (and append) stdout and stderr to file and terminal and get proper exit status
提问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 bash
flavours, is to turn on the pipefail
option:
另一种可能,有一些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 PIPESTATUS
functionality 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 R
to the return value of command1
, and pipe output of command1
to command2
, whose output is redirected to the output of parent shell.
它将变量设置R
为 的返回值command1
,以及command1
to 的管道输出command2
,其输出被重定向到父 shell 的输出。