据我所知,我可以使用 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
完成后command
,tee
将关闭命名管道,这将在每个管道上发出 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
, file2
and file3
,而是希望将相同的数据通过管道传输到三个命令cmd1
, cmd2
and cmd3
,即
… | ??? cmd1 cmd2 cmd3
应该等于
… | cmd1 &
… | cmd2 &
… | cmd3 &
只不过…
只会执行一次。
有两种方法可以做到这一点。
Ksh93、bash 和 zsh 支持流程替代。这是管道的概括,它允许命令的参数是一个文件,在写入时,将数据作为命令的输入传递(还有输入变体,在读取时,获取命令输出的数据) 。那是,
echo hello | tee >(cmd1)
打印hello
到标准输出并另外cmd1
作为hello
输入运行。
例如,如果您想复制 的输入somecommand
并将其传递给cmd1
和cmd2
,您可以使用
somecommand | tee >(cmd1) | cmd2
如果您的 shell 不支持进程替换,您可以使用命名管道。看阿尔切格的回答了解它是如何运作的。命名管道不如进程替换方便,因为您必须创建它们并删除它们,以及手动启动和同步进程。它们的优点是完全可移植,但并非所有 shell 都支持进程替换。它们还可以用于进程替换以外的场景。
在某些系统上,进程替换在内部使用命名管道。但在大多数系统上,它依赖于代表文件描述符的命名文件。
答案3
答案4
我很惊讶没有人提到pee
来自 moreutils 的命令(https://joeyh.name/code/moreutils)。