gpt4 book ai didi

bash - 寻找 shell 重定向交错行为的解释

转载 作者:行者123 更新时间:2023-11-29 09:26:06 26 4
gpt4 key购买 nike

给定以下脚本 (t.sh):

#!/bin/bash

if [ $# -eq 0 ]; then
log() {
{
if [ $# -gt 0 ]; then
printf -- %s\\n "$*"
else
cat
fi
} | tee -a logged.out
}
else
log() {
if [ $# -gt 0 ]; then
printf -- %s\\n "$*"
else
cat
fi
} > >(tee -a logged.out)
fi

declare -xf log

: > logged.out

./t2.sh 2>&1 | tee verbose.out

t2.sh 在哪里:

#!/bin/bash

echo outone
echo errone >&2

echo logged pipe | log

echo outtwo
echo errtwo >&2

log logged message

echo outthree
echo errthree >&2

我无法理解日志函数的两个版本之间的输出差异。

默认(第一个)函数执行我想要的操作,因为它在将记录的输出发送到 logged.out 时正确地交错 stdout、stderr 和 verbose.out 文件中的日志函数输出。

然而,第二个函数没有正确地将记录的输出与 stdout 和 stderr 输出交错,而是似乎缓冲了记录的输出,因此它最终在 verbose.out 文件的末尾(尽管这个输出顺序不是即使是一致的,记录的消息偶尔也会以相反的顺序出现在输出中,并且第一条消息可能会在输出中的某个地方出现得更早。

正确操作:

$ ./t.sh; more {logged,verbose}.out | cat
outone
errone
logged pipe
outtwo
errtwo
logged message
outthree
errthree
::::::::::::::
logged.out
::::::::::::::
logged pipe
logged message
::::::::::::::
verbose.out
::::::::::::::
outone
errone
logged pipe
outtwo
errtwo
logged message
outthree
errthree

错误操作:

$ ./t.sh broken; more {logged,verbose}.out | cat
outone
errone
outtwo
errtwo
outthree
errthree
logged message
logged pipe
::::::::::::::
logged.out
::::::::::::::
logged message
logged pipe
::::::::::::::
verbose.out
::::::::::::::
outone
errone
outtwo
errtwo
outthree
errthree
logged message
logged pipe

我确定这种行为是有原因的,我只是不知道它是什么。有没有大神能指教一下?

最佳答案

这是一个更简单的测试用例。为什么

echo foo | cat
echo bar

打印 foo 后跟 bar,而

echo foo > >(cat)
echo bar

先以 bar 倒序打印?

这是因为对于管道,bash 等待管道中的所有阶段完成。对于进程替换,进程只是简单地 fork 而不是等待。

这意味着在执行下一个语句之前,进程替换命令是否可以启动、读取和处理正在写入的内容存在竞争条件,并且在您的情况下它正在丢失。

你可以通过一个简单的实验更清楚地看到这个效果:

echo foo  |  sleep 10    # Waits 10 seconds
echo foo > >(sleep 10) # Finishes immediately

关于bash - 寻找 shell 重定向交错行为的解释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24006148/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com