Bash Can';t出口和t形三通执行的奇怪顺序
将函数的输出管道化到Bash Can';t出口和t形三通执行的奇怪顺序,bash,tee,zsh,Bash,Tee,Zsh,将函数的输出管道化到tee命令时,我遇到了一些奇怪的行为。第一个问题是,当从管道传输到tee的函数调用exit命令时,我无法退出程序。例如: myfunction(){ # Some stuff here exit 1 } myfunction | tee -a $UPGRADE_LOG 当我运行上述代码时,程序无法退出并运行到完成 我遇到的另一个问题是,tee似乎导致一些代码以这样的方式运行,顺序被撤消。我有以下输出: 显示系统范围和INSTATNCE内存使用情况: 您确定
tee
命令时,我遇到了一些奇怪的行为。第一个问题是,当从管道传输到tee
的函数调用exit
命令时,我无法退出程序。例如:
myfunction(){
# Some stuff here
exit 1
}
myfunction | tee -a $UPGRADE_LOG
当我运行上述代码时,程序无法退出并运行到完成
我遇到的另一个问题是,tee
似乎导致一些代码以这样的方式运行,顺序被撤消。我有以下输出:
显示系统范围和INSTATNCE内存使用情况:
您确定要备份给定当前内存限制的实例吗?[y/n]:已使用的文件系统大小可用率已安装%
/dev/mapper/system root 15G 13G 1.5G 90%/
日志文件大小:24K包的总大小:248K可用空间:1.5G
它应该在什么时候运行:
显示系统范围和INSTATNCE内存使用情况:
已使用的文件系统大小可用已安装的文件系统%
/dev/mapper/system root 15G 13G 1.5G 90%/
日志文件大小:24K包的总大小:248K可用空间:1.5G
您确定要备份给定当前内存限制的实例吗?[是/否]:
不使用
tee
时,一切正常。这些问题似乎相互关联。你知道为什么会这样吗?我应该怎么做?这个exit
语句退出进程运行的(子)shell。现在惊喜来了:
管道
管道是由一个控制操作符|
或|&
分隔的一个或多个命令的序列。管道的格式为:
[time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]
管道中的每个命令都作为单独的进程执行(即在子shell中)。
来源:manbash
因此,函数中的exit
语句只会终止管道的子shell。这实际上意味着exit
在管道中什么都不做
$ exit | exit | echo foo
foo
$ exit | exit
$ # shell not terminated
注意:这显然取决于shell,因为行为不同。告诉您为什么会发生这种情况。这一个告诉您如何修复它。:)
这里重要的是,我们不是使用常规管道,而是使用fortee
——因此myfunction
在shell本身而不是子shell中运行,因此退出
正确应用
至于为什么通过
tee
重定向stdout会取消stderr的同步,请参见请不要问多个问题,而是将它们分开。还要注意的是,如果你尽可能接近MCVE,你会增加获得好答案的机会:这些问题似乎与同一个问题有关,所以我把它们放在一起。很抱歉,如果它带来了任何混乱。不,代码不是非顺序运行的——所发生的是,您的stdout和stderr正在经历不同的进程,因此它们在不同的时间到达。不过,最初的写操作仍然是同时进行的。是的,我知道代码是按顺序运行的。我只是指出它的表现就是这样。我认为这是因为它们是分开运行的,我只是不知道为什么。谢谢你的澄清!“什么都不做”不是很准确exit 2 | exit 3 | true
将${PIPESTATUS[0]}
设置为2和${PIPESTATUS[1]}
设置为3,如果set-o pipefail
处于活动状态,则会导致整个管道的退出状态为3。尽管如此,这些效果并不是OP想要的@查理·达菲是真的。此外,如果设置了选项lastpipe
,它将对最后一个exit
语句产生影响(例如exit | exit
),此解决方案工作正常。谢谢你的解释!
with_logs_piped() {
local logfile=$1; 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