寻找解释外壳重定向交织行为 [英] Looking for explanation of shell redirection interleaving behaviour

查看:43
本文介绍了寻找解释外壳重定向交织行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Given the following script (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

我无法理解两个版本的log函数之间的输出差异.

I'm failing to understand the difference in the output between the two versions of the log function.

默认(第一个)功能实现了我想要的功能,它可以正确地将verbose.out文件中的stdout,stderr和log函数输出交织在一起,同时将已记录的输出发送到logging.out.

The default (first) function does what I want in that it correctly interleaves stdout, stderr, and the log function output in the verbose.out file while sending the logged output to logged.out.

但是,第二个功能不能正确地将记录的输出与stdout和stderr输出进行交织,而是似乎缓冲了记录的输出,因此最终在verbose.out文件的末尾(尽管此输出顺序不是甚至是一致的,并且日志记录的消息有时会以相反的顺序出现在输出中,并且第一条消息可以在输出中的某个位置更早地出现.

The second function however, does not correctly interleave the logged output with the stdout and stderr output and instead seems to buffer the logged output and it therefor ends up at the end of the verbose.out file (though this output ordering is not even consistent and the logged messages occasionally occur in the inverse order in the output and the first of the messages can appear earlier in the output somewhere).

正确操作:

$ ./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

我确定这种行为是有原因的,我只是不知道它是什么.有人可以启发我吗?

I'm sure there is a reason for this behaviour I just don't know what it is. Would someone be able to enlighten me?

推荐答案

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

Here's a simpler test case. Why does

echo foo | cat
echo bar

打印 foo 后跟 bar ,而

echo foo > >(cat)
echo bar

首先用 bar 以相反的顺序打印它们?

prints them in reverse order with bar first?

这是因为对于管道,bash等待管道中的所有阶段完成.对于流程替代,只需简单地分叉该流程,而无需等待.

This is because for a pipe, bash waits for all stages in the pipeline to finish. For process substitution, the process is simply forked off and not waited on.

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

This means that there's a race condition on whether the process substitution command can start, read and process what's being written to it before the next statements execute, and in your case it's losing.

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

You can see this effect more clearly with a simple experiment:

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

这篇关于寻找解释外壳重定向交织行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆