Shell 有没有像xargs这样的东西,它通过管道传输数据而不是使用参数?

Shell 有没有像xargs这样的东西,它通过管道传输数据而不是使用参数?,shell,parallel-processing,xargs,Shell,Parallel Processing,Xargs,xargs如果您有一个通过命令行参数接受其输入的命令,那么它非常有用,但是如果您有一个通过stdin接受其输入的命令,那么它就没有那么有用了 我所看到的对于这种情况的建议是使用tee将行复制到几个下游进程,如下所示: producer | tee>(consumer0>out0)>(consumer1>out1)>(consumer2>out2)| consumer3>out3; cat out*|管道的下一阶段 这有一个缺点,即所有消费者都会收到所有生成的行,并且假设消费者{0..3}是不同

xargs
如果您有一个通过命令行参数接受其输入的命令,那么它非常有用,但是如果您有一个通过stdin接受其输入的命令,那么它就没有那么有用了

我所看到的对于这种情况的建议是使用
tee
将行复制到几个下游进程,如下所示:

producer | tee>(consumer0>out0)>(consumer1>out1)>(consumer2>out2)| consumer3>out3;
cat out*|管道的下一阶段
这有一个缺点,即所有消费者都会收到所有生成的行,并且假设
消费者{0..3}
是不同的过程。如果我需要每个消费者都是相同的,并且处理部分输入(例如,并行化一个顺序消费者),那么它就不能正常工作

我要寻找的是一种类似于
xargs
的东西,它允许在同一消费者的多个实例之间分割工作,然后组合输入和继续处理。输出的组合方式应该模仿xargs,因此不能保证行的顺序,但两行不会拼接在一起(例如:“Hello Fred”和“Hello George”可能以任何顺序出现,但您不会看到“HHello GeoFregedello”)

这样做的主要用途是处理大量数据,如果为每行输入旋转一次,那么用户的启动延迟将是显而易见的。如果
consumer
的启动成本不高,我只需将其封装在一个小的shell脚本中,将其参数导入
consumer
并使用
xargs
调用即可

至少在我想到的用例中,生产者将从内部服务获取一组数据,之后消费者将需要转换这些数据并进行一些API调用。因此,生产者和消费者都将是长时间运行的进程,并行运行API调用确实会加快速度

像这样的东西很理想,但我找不到任何能做到这一点的东西:

producer |-P20用户|管道的下一阶段
是否有提供此功能的命令行工具

在同一使用者的多个实例之间拆分工作

这可以在
xargs
的消费者端完成

例:

将随机选择一个消费者

委员会:

将为每个使用者运行输入

不管怎样,你应该明白这个想法

对于您的T恤,无需任何临时文件即可轻松完成:

consumer() { sed "s/^/$1: /"; }
producer() { seq 3; }
next-stage-of-pipeline() { sed "s/^/Result: /"; }
producer |
{ tee >(consumer 0 >&10) >(consumer 1 >&11) >(consumer 2 >&12) | consumer 3 >&14 ;} 10>&1 11>&1 12>&1 14>&1 | 
next-stage-of-pipeline
如果您需要ex.为每个消费者将输入拆分为4,那么仍然很容易做到:

filter() { awk -vN="$1" '(NR + N) % 4 == 1'
producer |
{ tee >(
     filter 1 | consumer 0 >&10
) >(
     filter 2 | consumer 1 >&11
) >(
     filter 3 | consumer 2 >&12
) | 
     filter 4 | consumer 3 >&14 
;} 10>&1 11>&1 12>&1 14>&1 | 
next-stage-of-pipeline

我认为,
gnuparallel
可能会满足您的需求

producer | parallel consumer | next command in pipeline
编辑:直到我开始玩
parallel
,我才完全理解这个问题。Parallel可以将函数作为消费者,您可以在该函数中使用流

e、 g

编辑2:

您可以使用
--pipe
选项,该选项将数据传输到使用者。
-q
参数在使用者周围放置shell引号:

for i in {1..30}; do echo "foo $i bar"; done | parallel --pipe -q awk '{print $2}'
奖金:

  • parallel
    将在顺序处理器上运行作业。如果您有8个核心和16个消费者,每个核心将有2个消费者(这是可配置的)
  • parallel
    可以在网络上的多台机器上运行,只要它可以
    ssh
    发送到这些机器而不需要提示输入密码(例如,使用
    ssh代理

  • GNU Parallel可以将标准输入切碎到同一个命令:

    ... | parallel --pipe consumer
    
    默认情况下,它在
    \n
    上进行剪切,块大小约为1MB。这可以通过
    --recstart
    /
    --recend
    --block
    进行更改

    如果输入是文件,则速度更快:

    parallel -a bigfile --pipepart --block -1 consumer
    
    这将找到
    bigfile
    的大小,并为每个CPU线程将其拆分为一个块。这是动态完成的,因此不会创建临时文件

    的第9章详细介绍了这一点

    但如果您真的希望整个输入通过管道传输到不同的用户,GNU Parallel也可以做到这一点:

    # Pipe 1..10 to consumer-a..z
    seq 10 | parallel --pipe --tee 'echo consumer-{}; cat' ::: {a..z}
    

    您打算如何分割输入?逐行循环?第一个1/20到消费者0,下一个1/20到消费者1。。。?如何组合输出?理想情况下,它是可配置的,实际上,循环是最容易实现的,如果有这样一个工具,我所期望的可能是可用的(我认为这就是xargs如何将输入拆分为参数)。为了在存在大量输入的情况下以合理的方式进行操作,我希望输出不会提供任何保证,除了当作为工具stdout(基本上是xargs的行为)发出时不会混合行(空定界选项会很好),我不理解。如果
    consumer
    的速度很快,你就不能使用
    xargs-p20bash-c'consumer@KamilCuk,但是如果你使用像Java这样的语言编写的东西,这就不太理想了,因为它既有启动成本,而且运行时间越长,速度就越快。@Morgen为了避免额外的混乱,您能否澄清“生产者”是否“昂贵”(时间、内存、启动缓慢等),以及预期产生的数据量。让消费者/生产者并行运行很重要吗?我认为有一点需要注意,在POSIX系统上,只有当小于PIPE_BUF(例如,默认情况下没有缓冲stderr)时,才能保证缓冲写入是原子的。虽然我喜欢这是一个纯shell解决方案,但它不能很好地扩展到约20个消费者(当你必须重复几乎相同的代码时,很容易打错字)
    (…)
    不能缩放,而且从来没有缩放过。你可以在
    awk
    tho中做管道,所以你可以试试。除此之外,我想我们必须编写我们自己的工具来完成。但是,例如,最后一个代码片段能做到你想的吗?拆分
    ... | parallel --pipe consumer
    
    parallel -a bigfile --pipepart --block -1 consumer
    
    # Pipe 1..10 to consumer-a..z
    seq 10 | parallel --pipe --tee 'echo consumer-{}; cat' ::: {a..z}