将标准输出发送到链中的多个下游进程

将标准输出发送到链中的多个下游进程

我有一系列这样运行的命令:

cmd1 < input > foo
cmd2 < foo > bar
cmd3 foo bar > output

有没有办法在没有中间文件的情况下做到这foo一点bar

我还想避免运行cmd1两次:

cmd3 <(cmd1 < input) <(cmd1 < input | cmd2) > output

所有 3 个命令可能需要数小时才能运行,文件大小在 1GB 到 100GB 范围内(生物信息学)。

这是一个人为但可运行的示例:

function cmd1 { sed -r 's/[246]/x/g'; }
function cmd2 { sed -r 's/[135]/-/g'; }
function cmd3 { paste $1 $2; }
seq 10 > input
cmd3 <(cmd1 < input) <(cmd1 < input | cmd2)  # cmd1 runs twice

输出

1       -
x       x
3       -
x       x
5       -
x       x
7       7
8       8
9       9
10      -0

不确定这是否有帮助,但我希望数据像这样流动:

input --> cmd1 ---> cmd2  -->|
                |            |--> cmd3  --> output
                ------------>|

https://unix.stackexchange.com/a/43536很接近,但还不够。

答案1

像这样的事情,可能吗?

rm -f fifo
mkfifo fifo

cmd1 <input | tee fifo | cmd2 | cmd3 fifo /dev/stdin >output

这将创建一个名为 的命名管道fifo。第一个命令使用 写入命名管道和第二个命令的标准输入tee。第三个命令从命名管道和标准输入读取。

没有任何中间数据存储在磁盘上,但是如果cmd3在管道缓冲区已满之前不从命名管道中进行消耗,或者如果cmd2与它消耗的数据量相比生成的数据非常少,则管道可能会死锁(而且,最重要的是,在管道缓冲区满之前没有产生足够的cmd3消耗)。fifo你可以可能通过使用诸如pv缓冲来自命名管道的数据之类的方法来解决此问题,如使用cmd3 <( pv --quiet <fifo ) /dev/stdin或在编写器站点使用tee >( pv --quiet >fifo )(或其某些变体)。

相关内容