我想管道标准输出的程序,同时保持它在屏幕上。

通过一个简单的例子(这里使用echo只是为了说明):

$ echo 'ee' | foo ee <-我想看到的输出

我知道tee可以复制stdout到文件,但这不是我想要的。 $ echo 'ee' | tee output.txt | foo

我试着 $ echo 'ee' | tee /dev/stdout | foo但它不起作用,因为tee输出到/dev/stdout是通过管道输出到foo的


这里是一个适用于任何Unix / Linux实现的解决方案,假设它关心遵循POSIX标准。它也适用于一些非Unix环境,比如cygwin。

echo 'ee' | tee /dev/tty | foo

参考:开放组基础规范第7期 IEEE Std 1003.1, 2013版,§10.1:

/dev/tty 与该进程的进程组相关联(如果有)。它是 对于希望确定的程序或shell过程很有用 无论以何种方式向终端写入消息或从终端读取数据 输出已重定向。它还可以用于 当需要输入输出时,要求输出文件的名称 查找当前正在使用的终端是一件令人厌烦的事情。在每个进程中,控制终端的同义词

据报道,一些环境(如谷歌Colab)在tty命令返回可用设备的同时没有实现/dev/tty。这里有一个变通办法:

tty=$(tty)
echo 'ee' | tee $tty | foo

或者用古老的伯恩壳:

tty=`tty`
echo 'ee' | tee $tty | foo

Try:

$ echo 'ee' | tee /dev/stderr | foo

当然,如果可以选择使用stderr。

另一件可以尝试的事情是:

echo 'ee' | tee >(foo)

>(foo)是一个进程替换。

编辑: 为了更清楚一点,(.)在这里启动一个新的子进程到当前终端,输出将被重定向到该终端。

echo ee | tee >(wc | grep 1)
#              ^^^^^^^^^^^^^^ => child process

除了子进程中的任何变量声明/更改都不会反映在父进程中之外,在子进程中运行命令几乎没有什么需要关注的。

首先,你需要找出与你的屏幕(或任何你想在屏幕上显示输出的屏幕)相关的终端:

tty

然后你可以将输出tee到该终端,并通过你的foo程序管道另一个副本:

echo ee | tee /dev/pty/2 | foo

在某些系统上拒绝访问“/dev/stdout”,但是通过“/dev/tty”可以访问用户终端。 使用"wc"代替"foo",上面的例子可以正常工作(在linux, OSX等):

% echo 'Hi' | tee /dev/tty | wc 嗨 1 1 3

为了在匹配文件列表的底部添加一个计数,我使用如下代码: % ls [A-J]* | tee /dev/tty | wc -l

为了避免记住这些,我定义了别名: %别名t tee /dev/tty % alias WCL wc -l

这样我就可以简单地说: % l [A-J]* bb0 t bb1 wcl


附言:对于年轻人来说,他们可能会因为“titty”的发音而窃笑,我可以补充一点,“tty”曾经很常见 “电传打字机”终端的缩写,使用一卷黄色 纸做的,还有经常卡住的圆钥匙。