是否可以将一个命令的输出重定向到多个命令?

是否可以将一个命令的输出重定向到多个命令?

据我所知,我可以使用 tee 命令将标准输出拆分到屏幕和其他文件上:

command -option1 -option2 argument | tee file1 file2 file3 

是否可以使用 tee 将输出重定向到命令而不是文件,以便理论上可以创建命令链?

答案1

您可以使用命名管道(http://linux.die.net/man/1/mkfifo)在命令行上tee并在命名管道上读取命令。

mkfifo /tmp/data0 /tmp/data1 /tmp/data2
cmd0 < /tmp/data0 & cmd1 < /tmp/data1 & cmd2 < /tmp/data2 &
command -option1 -option2 argument | tee /tmp/data0 /tmp/data1 /tmp/data2

完成后commandtee将关闭命名管道,这将在每个管道上发出 EOF(读取 0 字节)信号,/tmp/dataN通常会终止cmdN进程。真实例子:

$ mkfifo /tmp/data0 /tmp/data1 /tmp/data2
$ wc -l < /tmp/data0 & wc -w < /tmp/data1 & wc -c < /tmp/data2 &
$ tee /tmp/data0 /tmp/data1 /tmp/data2 < /etc/passwd >/dev/null
$ 61
1974
37

由于后台进程的存在,shell 在程序输出之前返回了一个提示符。所有三个实例均wc正常终止。

答案2

如果我理解正确,您正在寻找 的等效项tee file1 file2 file3,但不是将相同的数据写入三个文件file1, file2and file3,而是希望将相同的数据通过管道传输到三个命令cmd1, cmd2and cmd3,即

… | ??? cmd1 cmd2 cmd3

应该等于

… | cmd1 &
… | cmd2 &
… | cmd3 &

只不过只会执行一次。

有两种方法可以做到这一点。

Ksh93、bash 和 zsh 支持流程替代。这是管道的概括,它允许命令的参数是一个文件,在写入时,将数据作为命令的输入传递(还有输入变体,在读取时,获取命令输出的数据) 。那是,

echo hello | tee >(cmd1)

打印hello到标准输出并另外cmd1作为hello输入运行。

例如,如果您想复制 的输入somecommand并将其传递给cmd1cmd2,您可以使用

somecommand | tee >(cmd1) | cmd2

如果您的 shell 不支持进程替换,您可以使用命名管道。看阿尔切格的回答了解它是如何运作的。命名管道不如进程替换方便,因为您必须创建它们并删除它们,以及手动启动和同步进程。它们的优点是完全可移植,但并非所有 shell 都支持进程替换。它们还可以用于进程替换以外的场景。

在某些系统上,进程替换在内部使用命名管道。但在大多数系统上,它依赖于代表文件描述符的命名文件

答案3

至少在您可以mkfifo使用进程替换来跳过:

command -option1 -option2 argument | tee >(cmd1) >(cmd2) >(cmd3)

或采用阿尔切的例子

tee >(wc -l) >(wc -w) >(wc -c) < /etc/passwd >/dev/null

答案4

我很惊讶没有人提到pee来自 moreutils 的命令(https://joeyh.name/code/moreutils)。

相关内容