代理 stdout/stderr 在 bash 中保持秩序
Proxy stdout/stderr keeping order in bash
我正在尝试在文件输出的每一行前面添加一些信息,方法是:
- 捕获标准输出和标准错误
- 预置信息
- 输出到原句柄
这是我的测试脚本:
#!/bin/bash
#
# Test proxying stdout and stderr
#
function proxy-stdouterr() {
local name=""
local handle=
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 ]
我该如何解决这个问题?
谢谢
正如其他人所指出的,这是一个同步问题,没有明显的
在不知道更多关于您具体控制哪些部分的情况下回答
想要改变。
恕我直言,主要有两个攻击面:
流缓冲。大多数 C 派生程序不缓冲 stderr,
如果它们是终端和缓冲区,则逐行缓冲标准输入和标准输出
他们完全不同。这解释了为什么 stderr 总是出现
在你的例子中首先出现。一个廉价的应对方法是使用 /usr/bin/echo
而不是内置 echo
,所以你会在最后得到一个刷新的流
每一行(以及进程生成的大量延迟)。它解决了
你的例子 100% 是我试过的,所以对你来说可能就足够了
也。如果您可以控制生成这些行的命令,
确保 stdout 和 stderr 都是行缓冲的。
进程调度。你有两个进程竞争读取
两个流。如果当时两者都有数据流动,
他们在互相竞争。您可以通过以下方式减轻这种情况
让一个进程来做,但我不确定是否有可能
在原生 bash
中保持高效(不可编程 POSIX select
最终用户可用)
无论如何,如果图片中的任何地方都在排队,你就是
就保持订单而言,搞砸了。
我正在尝试在文件输出的每一行前面添加一些信息,方法是:
- 捕获标准输出和标准错误
- 预置信息
- 输出到原句柄
这是我的测试脚本:
#!/bin/bash
#
# Test proxying stdout and stderr
#
function proxy-stdouterr() {
local name=""
local handle=
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 ]
我该如何解决这个问题?
谢谢
正如其他人所指出的,这是一个同步问题,没有明显的 在不知道更多关于您具体控制哪些部分的情况下回答 想要改变。
恕我直言,主要有两个攻击面:
流缓冲。大多数 C 派生程序不缓冲 stderr, 如果它们是终端和缓冲区,则逐行缓冲标准输入和标准输出 他们完全不同。这解释了为什么 stderr 总是出现 在你的例子中首先出现。一个廉价的应对方法是使用
/usr/bin/echo
而不是内置echo
,所以你会在最后得到一个刷新的流 每一行(以及进程生成的大量延迟)。它解决了 你的例子 100% 是我试过的,所以对你来说可能就足够了 也。如果您可以控制生成这些行的命令, 确保 stdout 和 stderr 都是行缓冲的。进程调度。你有两个进程竞争读取 两个流。如果当时两者都有数据流动, 他们在互相竞争。您可以通过以下方式减轻这种情况 让一个进程来做,但我不确定是否有可能 在原生
bash
中保持高效(不可编程 POSIXselect
最终用户可用)
无论如何,如果图片中的任何地方都在排队,你就是 就保持订单而言,搞砸了。