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

Posted

技术标签:

【中文标题】管道命令输出到 tee 但也保存命令的退出代码 [重复]【英文标题】:Piping command output to tee but also save exit code of command [duplicate] 【发布时间】:2011-10-15 20:34:49 【问题描述】:

我有一个 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 的返回码,但仍将输出通过管道传输到日志文件?

【问题讨论】:

【参考方案1】:

您可以设置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

【讨论】:

这似乎是一个比公认的解决方案更优雅的解决方案 同意。接受的答案要求您提前知道管道中的哪个命令会失败。如果您将 5 个不同的命令连接在一起,您将不得不猜测数组中的哪一个会失败。 或者在 PIPESTATUS 上做一个循环 恢复原来的管道设置:$ set +o pipefail 注意,pipefail 在 ubuntu 上也被 dash 支持【参考方案2】:

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

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

【讨论】:

如下所述,如果您有多个管道,则需要检查每个命令的状态以了解失败的位置。 完美运行,谢谢。 也很重要:变量是短暂的,所以即使“回显”它也会让你失去运行管道的价值。将其分配给另一个变量,除非您将立即访问它,并且只访问一次。【参考方案3】:

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

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

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

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

【讨论】:

我希望最终答案不是特定于 shell 的(即:仅限 bash)。 完美!我更喜欢这个不仅仅依赖 bash :-) 谢谢@Demosthenex 但我使用 ( ) 而不是 来捕获输出 ....【参考方案4】:

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

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

【讨论】:

我们可以用read e < $f而不是cat保存一个fork吗? 当然。并且您可能想要创建一个临时文件以避免竞争条件。但是,正如您所看到的,还有更好的解决方案......

以上是关于管道命令输出到 tee 但也保存命令的退出代码 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

tee命令

shell运行下的写日志

将管道添加到 tee-d 文件的简单方法

Linux命令之保存命令结果到文件并且输出到屏幕tee

Linux命令使用:tee

Linux命令使用:tee