管道命令输出到tee但也保存命令的退出代码

时间:2011-07-29 10:36:42

标签: bash shell pipe sh tee

我有一个shell脚本,我在其中包装一个命令(mvn clean install),将输出重定向到日志文件。

#!/bin/bash
...
mvn clean install $@ | tee $logfile
echo $? # Does not show the return code of mvn clean install

现在,如果mvn clean install因错误而失败,我希望我的包装器shell脚本也会因该错误而失败。但由于我将所有输出传递给tee,我无法访问mvn clean install的返回码,因此当我之后访问$?时,它始终为0(因为tee成功)。

我尝试让命令将错误输出写入单独的文件并在之后检查,但mvn的错误输出始终为空(看起来它只写入stdout)。

如何保留mvn clean install的返回码但仍将输出汇总到日志文件?

4 个答案:

答案 0 :(得分:173)

您可以设置pipefail shell option选项以获得所需的行为。

来自Bash Reference Manual

  

管道的退出状态是最后一个命令的退出状态   在管道中,除非启用pipefail选项(请参阅The Set Builtin)。   如果启用了pipefail,则管道的返回状态为   以非零状态退出的最后(最右边)命令的值,   如果所有命令都成功退出,则为零。

示例:

$ false | tee /dev/null ; echo $?
0
$ set -o pipefail
$ false | tee /dev/null ; echo $?
1

恢复原始管道设置:

$ set +o pipefail

答案 1 :(得分:131)

由于您正在运行bash,因此您可以使用其$PIPESTATUS变量而不是$?

mvn clean install $@ | tee $logfile
echo ${PIPESTATUS[0]}

答案 2 :(得分:11)

你可以运行mvn命令并缓存退出代码......我的例子使用“false”命令。

$ { false ; echo $? > /tmp/false.status ; } | tee $logfile
$ cat /tmp/false.status
1

通过这种方式,您可以使用状态文件内容做出进一步的决定。

我现在很好奇是否有更有说服力的方法来实现这一目标。

答案 3 :(得分:3)

解决方法(注意:perfer @ Frederic的解决方案):

f=`mktemp`
(mvn clean install $@; echo $?>$f) | tee $logfile
e=`cat $f` #error in variable e
rm $f
相关问题