要将stdout和stderr重定向(并追加)到文件中,同时在终端上显示它,我这样做:
command 2>&1 | tee -a file.txt
但是,还有另一种方法可以做到这一点,以便我获得退出状态的准确值吗?
也就是说,如果我测试$?
,我希望看到command
的退出状态,而不是tee
的退出状态。
我知道我可以在这里使用${PIPESTATUS[0]}
而不是$?
,但我正在寻找另一种不需要检查PIPESTATUS
的解决方案。
答案 0 :(得分:30)
也许您可以将PIPESTATUS的退出值放入$?
command 2>&1 | tee -a file.txt ; ( exit ${PIPESTATUS} )
答案 1 :(得分:6)
有一些bash
种口味的另一种可能性是打开pipefail
选项:
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
答案 2 :(得分:4)
使用流程替换:
command > >( tee -a "$logfile" ) 2>&1
tee在子shell中运行所以$?保持命令的退出状态。
答案 3 :(得分:3)
有一种神秘的POSIX方式:
exec 4>&1; R=$({ { command1; echo $? >&3 ; } | { command2 >&4; } } 3>&1); exec 4>&-
它会将变量R
设置为command1
的返回值,并将command1
的管道输出设置为command2
,其输出将重定向到父shell的输出