203

我有一个 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 的错误输出始终为空(似乎它只写入标准输出)。

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

4

4 回答 4

300

您可以将pipefail shell option选项设置为 on 以获得您想要的行为。

来自Bash 参考手册

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

例子:

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

要恢复原始管道设置:

$ set +o pipefail
于 2011-07-29T11:05:14.987 回答
200

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

mvn clean install $@ | tee $logfile
echo ${PIPESTATUS[0]}
于 2011-07-29T10:42:19.487 回答
17

您可以运行 mvn 命令并缓存退出代码...我在示例中使用“false”命令。

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

这样您就可以使用状态文件的内容来做出进一步的决定。

我现在很好奇是否有更雄辩的方法来实现这一点。

于 2011-07-29T10:55:59.697 回答
5

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

f=`mktemp`
(mvn clean install $@; echo $?>$f) | tee $logfile
e=`cat $f` #error in variable e
rm $f
于 2011-07-29T10:56:00.783 回答