我试图在 bash 脚本中逐行收集几个子进程的输出,以便将其转发到另一个进程。
我没有发现任何东西可以保证子流程的输出不会混合,但对我来说重要的是每条输出线都正确地连接到输出端。输出之间的顺序无关紧要。
这是混合/乱码输出的示例:
#!/bin/bash
for i in {1..1000}; do
( { echo BEGIN; dmesg; echo END; } | tr -d '\n'; echo ) &
done
wait
运行这个:
$ ./test_output.sh | perl -ne 'print "$1\n" if m/(.{1,20}BEGIN.{0,20})/' | head
0.000000] SRAT: PXMBEGIN[ 0.000000] Initi
ME through PCIe PME BEGIN[ 0.000000] Initi
ME through PCIe PME BEGIN[ 0.000000] Initi
[ 0.209816] pci 0BEGIN[ 0.000000] Initi
ciehp 0000:00:16.1:pBEGIN[ 0.000000] Initi
CI: Updating contextBEGIN[ 0.000000] Initi
l family 2[ 0.588BEGIN[ 0.000000] Initi
ME through PCIe PME BEGIN[ 0.000000] Initi
CI: Updating contextBEGIN[ 0.000000] Initi
3922 pages, LIFO batBEGIN[ 0.000000] Initi
您可以看到多行内容混合。
当然,没有&
一切都很好。
所以现在,我别无选择,只能将每个孩子的输出重定向到一个文件,然后在一个 big 之后wait
,cat
所有这些文件。
使用 GNU 并行运行相同的工作可以完成部分工作,但在我的环境中它不是一个选项。
GNU 并行确保命令的输出与按顺序运行命令时的输出相同。这使得使用 GNU 并行的输出作为其他程序的输入成为可能。
因此 GNU 并行将在每个作业完成后立即写入每个作业输出,并且它会注意不混合输出。那挺好的。但我也有兴趣尽快获得每个作业的输出,即不等待作业退出。有“-u”开关,但它会混合作业输出。
我是否需要玩 fifo、选择甚至编写 perl 脚本?
--
我想我已经找到了为什么/如何/何时输出在 man 7 管道中混合
POSIX.1-2001 说小于 PIPE_BUF 字节的 write(2)s 必须是原子的:输出数据作为连续序列写入管道。超过 PIPE_BUF 字节的写入可能是非原子的:内核可能会将数据与其他进程写入的数据交错。POSIX.1-2001 要求 PIPE_BUF 至少为 512 字节。(在 Linux 上,PIPE_BUF 为 4096 字节。)