能否将STDIN分发到并行进程中?

9

假设有以下标准输入示例:

foo
bar bar
baz
===
qux
bla
===
def
zzz yyy

能否将其根据分隔符(在本例中为“ ===”)进行拆分,并将其通过stdin馈送到并行运行的命令中?

因此,上面的示例输入将导致3个并行进程(例如名为do.sh的命令)其中每个实例都会在STDIN上接收部分数据,如下所示:

do.sh(实例1)通过STDIN接收到以下内容:

foo
bar bar
baz

do.sh(第二个实例)通过STDIN接收此内容:

qux
bla

do.sh(实例3)从标准输入接收到以下内容:

def
zzz yyy

我想使用xargs或GNU parallel可能可以实现这样的功能,但我不知道如何操作。
3个回答

13

从20110205版本开始,GNU Parallel可以实现这个功能。

cat | parallel --pipe --recend '===\n' --rrs do_stuff

4
这个答案可能需要更多的解释:pipe会导致并行写入标准输入而不是传递参数,recend表示记录结束,即分割字符串,rrs代表删除记录开始,即删除 '===\n'。除此之外,--keep-order很有用。 - Caesar

3
一般而言,不行。这种评估的原因之一是,标准I/O从文件中读取数据而非终端,每次读取BUFSIZ字节的数据块,其中BUFSIZ通常是2的幂,如512或更大。如果数据在文件中,一个进程将读取整个文件,其他进程将看不到任何东西(如果它们共享相同的打开文件描述符,则类似于文件描述符,但是多个文件描述符可以共享相同的打开文件描述符,并且可能位于不同的进程中),或者如果它们没有共享相同的打开文件描述符,则会读取整个相同的文件。
因此,您需要一个进程来读取文件,该进程知道它需要将信息分配给三个进程,并且需要知道如何连接到这三个进程。可能是您的分销程序运行三个进程并写入它们各自的管道输入。或者它可以是分销商连接到三个套接字并写入不同的套接字。
您的示例未显示/描述如果有37个由标记分隔的部分会发生什么。
我有一个自制程序叫做tpipe,类似于Unix的tee命令,但它会将其标准输入的副本写入每个进程和默认的标准输出。这可能是您所需的基础(至少涵盖了进程管理部分)。如果您需要,请联系我获取副本-请参见我的个人资料。
如果您正在使用Bash,可以使用带有进程替换的常规tee来模拟tpipe。请参阅此article以了解详细信息。
另请参见SF 96245,其中包含相同信息的另一版本 - 以及一个名为pee的程序的链接,该程序与tpipe非常相似(基本思路相同,在各个方面实现略有不同)。

tpipepee 有什么不同? - Ole Tange
1
我写了tpipe,之前没有听说过pee。但是有人有同样的基本需求并实现它并不让我感到惊讶。我不确定你能否猜到通过谷歌搜索“pee”有多难(即使使用“site:gnu.org pee”也会出现垃圾邮件)!因此,如果没有软件的URL,我无法为您进行比较和对比。 - Jonathan Leffler
2
http://serverfault.com/questions/96245/linux-debian-what-does-pee-in-moreutils-do 展示了如何使用 pee 命令,并且演示了在 bash 中不需要使用 pee 的方法:cat file | tee >(command1 >out1) >(command2 >out2) - Ole Tange
@Ole:感谢提供链接。我注意到pee在多个方面与tpipe的语义不同,最显著的是,tpipe会一直写入可用管道,直到它们全部关闭,而不像pee那样在第一个错误时停止。如果bash在所有感兴趣的平台上都可靠地可用,则bash工具很好,这可以节省我的工作。 (我的答案末尾的URL指向相同的符号,但不是您提供的文章)。 - Jonathan Leffler

1
你可以使用命名管道来实现这一点。 命名管道允许您将标准管道视为文件。 您可以拥有多个命名管道,并让其他程序处理它们。
我对命名管道并不是很熟悉,但我偶尔会在这种情况下使用它们。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接