带有代码块和管道的 shell 退出代码

Posted

技术标签:

【中文标题】带有代码块和管道的 shell 退出代码【英文标题】:shell exit code with code-block and pipe 【发布时间】:2015-01-14 16:07:04 【问题描述】:

在一个 shell 脚本中,我使用带有大括号的代码块将所有输出通过管道传输到控制台,并使用带有 tee 的日志文件。

#!/bin/bash


  echo "Foo bar"
  echo "foo bar on STDERR" >&2
  ERRL=66
  exit 99
 2>&1 | tee log-file.log

(这只是一个小演示脚本,原来的要复杂得多)

问题是,exit 99 行无效,脚本以退出代码 0 结束。(我认为这是 tee 命令的退出代码)

我尝试在脚本末尾添加行 exit $ERRL,但它显示变量 $ERRL 在大括号外为空。

当代码块中出现问题时,我该怎么做才能以错误代码结束脚本 - 而不会丢失日志文件的输出?

【问题讨论】:

检查 bash PIPESTATUS 数组。见tldp.org/LDP/abs/html/internalvariables.html 嘘,咝咝作响:链接到 ABS——它只是偶尔维护,而且在不完全不准确的情况下会展示不良做法,这是相当臭名昭著的。诚然,该特定页面还不错(有点过时,但没有明显的完全错误),但回顾之前的那些页面,第 9.2 节完全缺少一些 bash 4.3 更新,并显示 非常在有可靠变量类型可用时识别变量类型的方法很容易出错。 【参考方案1】:

重定向整个脚本输出的干扰最小的方法是预先这样做一次,而不涉及任何阻塞构造:

exec > >(tee log-file.log) 2>&1 # redirect stdout and stderr to a pipe to tee

echo "Foo bar"
echo "foo bar on STDERR" >&2
ERRL=66
exit 99

其他选项包括使用pipefail 设置...

set -o pipefail
 ...  2>&1 | tee log-file.log

...或在事后显式拉出退出状态:

 ...  2>&1 | tee log-file.log
exit "$PIPESTATUS[0]"

...或者只是使用不是管道的重定向:

 ...  > >(tee log-file.log) 2>&1

【讨论】:

我为我的脚本选择了 PIPESTATUS 解决方案,因为我只需要添加一行。但是下次我写类似的东西时,我会选择执行解决方案。【参考方案2】:

这是因为退出代码是管道中的 last 命令之一,除非您在管道之前有set -o pipefail。与@jimmcnamara hinted 一样,$PIPESTATUS array 包含管道中每个命令的退出代码,其顺序与原始管道相同。

【讨论】:

以上是关于带有代码块和管道的 shell 退出代码的主要内容,如果未能解决你的问题,请参考以下文章

代码块和作用域

代码块和并发性

静态代码块和实例化代码块

两个案例,解读静态代码块和构造代码块

java-普通代码块构造代码块和静态代码块的区别。

Java 重学系列之匿名代码块和静态代码块区别