shell 使用代码块和管道退出代码

shell exit code with code-block and pipe

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

#!/bin/bash

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

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

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

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

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

那是因为退出代码是管道中的 last 命令之一,除非管道之前有 set -o pipefail。由于 , the $PIPESTATUS array 包含管道中每个命令的退出代码,与原始管道的顺序相同。

重定向整个脚本输出的侵入性最小的方法是预先执行一次,不涉及任何阻塞结构:

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