无法使用 tee 退出和奇怪的执行顺序

Can't exit and strange order of execution with tee

将函数的输出通过管道传送到 tee 命令时,我遇到了一些奇怪的行为。第一个问题是,当从管道传送到 tee 的函数调用时,我无法使用 exit 命令退出程序。例如:

myfunction(){
    # Some stuff here
    exit 1
}

myfunction | tee -a $UPGRADE_LOG

当我运行上述代码时,程序无法退出并运行s完成。

我遇到的另一个问题是 tee 似乎导致某些代码以 运行 的方式取消顺序。我有以下输出:

SHOWING SYSTEM-WIDE AND INSTATNCE MEMORY USAGE:
Are you sure you would like to back up the instance given current memory contraints? [y/n]: Filesystem                           Size   Used  Avail  Use%  Mounted on
/dev/mapper/system-root              15G    13G   1.5G   90%   /
Log File Size: 24K   Total Size to Package: 248K Available Space: 1.5G

什么时候应该 运行 为:

SHOWING SYSTEM-WIDE AND INSTATNCE MEMORY USAGE:
Filesystem                           Size   Used  Avail  Use%  Mounted on
/dev/mapper/system-root              15G    13G   1.5G   90%   /
Log File Size: 24K   Total Size to Package: 248K Available Space: 1.5G
Are you sure you would like to back up the instance given current memory contraints? [y/n]: 

不使用 tee 时一切正常。这些问题似乎彼此相关。知道为什么会这样吗?我应该怎么做?

exit语句退出(sub-)shell进程在运行中。现在惊喜来了:

Pipelines

A pipeline is a sequence of one or more commands separated by one of the control operators | or |&. The format for a pipeline is:

[time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]

<snip>

Each command in a pipeline is executed as a separate process (i.e., in a subshell).

source: man bash

因此,函数中的 exit 语句只是终止了管道的子 shell。这实际上意味着 exit 在管道中什么都不做

$ exit | exit | echo foo
foo
$ exit | exit
$ # shell not terminated

注意: 这显然是 shell 相关的,因为 的行为不同。

告诉你为什么会这样。这个告诉你如何修复它。 :)

with_logs_piped() {
  local logfile=; shift
  "$@" > >(tee -a -- "$logfile") 2>&1  # 2>&1 redirects stderr through the same tee so it's
}                                      # ...also logged, and shows up sync'd with stdout.

myfunction() {
    # Some stuff here
    exit 1
}

with_logs_piped "$UPGRADE_LOG" myfunction

这里重要的是,我们没有使用常规管道,而是为 tee 使用 process substitution——因此 myfunction 在您的 shell 本身中运行, 不是 subshell,所以 exit 适用。


至于为什么通过 tee 重定向 stdout 会使 stderr 不同步,请参阅