代理stdout / stderr在bash中保持顺序

时间:2015-07-24 10:27:35

标签: bash stdout stderr

我正在尝试通过以下方式在文件的每一行输出前添加一些信息:

  • 捕获stdout和stderr
  • 预先填写信息
  • 输出到原始句柄

这是我的测试脚本:

#!/bin/bash
#
# Test proxying stdout and stderr
#

function proxy-stdouterr() {
    local name="$1"
    local handle=$2
    while IFS='' read -r line
    do
        echo -e "[ ${name}: ${line} ]" >&${handle}
    done
}

# Output some messages and attempt to parse them
(
    echo "1: Normal message"
    echo "2: Error" >&2
    echo "3: Normal message"
    echo "4: Error" >&2
) 2> >(proxy-stdouterr "stderr" 2) > >(proxy-stdouterr "stdout" 1)

这种方法效果很好但不保留终端中的顺序(Ubuntu 12.04)。

不代理输出时:

1: Normal message
2: Error
3: Normal message
4: Error

然而,代理订单时并未保留。更糟糕的是,这不是确定性的,大部分时间都是:

[ stderr: 2: Error ]
[ stderr: 4: Error ]
[ stdout: 1: Normal message ]
[ stdout: 3: Normal message ]

但偶尔:

[ stderr: 2: Error ]
[ stdout: 1: Normal message ]
[ stderr: 4: Error ]
[ stdout: 3: Normal message ]

我该如何解决这个问题?

由于

1 个答案:

答案 0 :(得分:1)

正如其他人所说,这是一个没有明显的同步问题 回答时不知道你特别控制哪些部分 并希望改变。

恕我直言有两个主要攻击面:

  • 流缓冲。大多数C派生程序不缓冲stderr, 如果它们是终端和缓冲区,则按行缓冲stdin和stdout 完全不然。这就解释了为什么斯特德尔总是会来 在你的例子中首先。廉价的警察是使用/usr/bin/echo 而不是内置echo,所以你最后得到一个刷新的流 每一行(以及过程产生的大量延迟)。它解决了 你的例子100%是我尝试过的,所以对你来说已经足够了 太。如果您对生成线条的命令有控制权, 确保stdout和stderr都是行缓冲的。

  • 进程安排。您有两个竞争过程的进程 两个流。如果当时有数据流动, 他们互相竞争。你可以减轻它 只有一个过程可以做到这一点,但我不确定它是否可行 保持原生bash的效率(无可编程POSIX select 最终用户可以使用)

在任何情况下,如果在图片中的任何地方排队,那么你就是 在保持秩序的情况下搞砸了。