我想管道程序的标准输出,同时将其保留在屏幕上。
举个简单的例子(这里使用的 echo
仅用于说明目的):
$ echo 'ee' | foo
ee
<- 我想看到的输出
我知道 tee 可以将标准输出复制到文件中,但这不是我想要的。
$ echo 'ee' | tee output.txt | foo
我试过
$ echo 'ee' | tee /dev/stdout | foo
但它不起作用,因为到 /dev/stdout
的 tee 输出通过管道传输到 foo
echo 'ee' | tee /dev/stderr
有效,所以如果您的 “在屏幕上” 要求也被 stderr 满足,那就可以了。
这是一个适用于任何 Unix/Linux 实现的解决方案,假设它关心遵循 POSIX
标准。它也适用于一些非 Unix 环境,例如 cygwin
。
echo 'ee' | tee /dev/tty | foo
参考:The Open Group Base Specifications Issue 7 IEEE Std 1003.1, 2013 Edition, §10.1:
/dev/tty 与该进程的进程组相关联,如果有的话。无论输出如何重定向,它对于希望确保向终端写入消息或从终端读取数据的程序或 shell 过程很有用。它也可以用于要求输出文件名的应用程序,当需要键入输出并且查找当前正在使用的终端很烦人时。在每个进程中,控制终端的同义词
据报道,某些环境(如 Google Colab)未实施 /dev/tty
,但仍让其 tty
命令返回可用设备。这是一种解决方法:
tty=$(tty)
echo 'ee' | tee $tty | foo
或使用古老的 Bourne 贝壳:
tty=`tty`
echo 'ee' | tee $tty | foo
另一件要尝试的事情是:
echo 'ee' | tee >(foo)
>(foo)
是一个 process substitution。
编辑:为了更清楚一点,(。)在这里启动一个新的子进程到当前终端,输出被重定向到。
echo ee | tee >(wc | grep 1)
# ^^^^^^^^^^^^^^ => child process
除了子进程中的任何变量声明/更改不会反映在父进程中之外,在子进程中运行命令几乎没有问题。
foo
输出上的任何进一步管道都必须成为流程替换的一部分。这是一个示例:echo 'ee' | tee file.txt >(wc -c | tr -d ' ')
echo 'ee' | tee >(cat) | foo | bar
的输出。
foo
看到 2x ee
并且终端上没有打印任何内容。尝试 echo 'ee' | tee >(cat) | grep .
与 echo 'ee' | tee >(cat) | grep x
。
尝试:
$ echo 'ee' | tee /dev/stderr | foo
当然,如果使用 stderr 是一种选择。
在某些系统上拒绝访问“/dev/stdout”,但访问用户终端是由“/dev/tty”提供的。对“foo”使用“wc”,上面的例子可以正常工作(在 linux、OSX 等上):
% 回声“嗨”|三通 /dev/tty |厕所 嗨 1 1 3
要在匹配文件列表的底部添加计数,我使用如下内容:
% ls [A-J]* | tee /dev/tty | wc -l
为了避免记住所有这些,我定义了别名:
% alias t tee /dev/tty
% alias wcl wc -l
所以我可以简单地说:
% ls [A-J]* | t | wcl
后记:对于可能会嘲笑它的发音为“titty”的年轻人,我可能会补充说,“tty”曾经是“电传打字机”终端的常见缩写,它使用一卷黄纸并有圆形键,通常卡住。
首先,您需要找出与您的屏幕关联的终端(或您希望输出显示的任何屏幕):
tty
然后您可以将输出发送到该终端并通过您的 foo 程序管道另一个副本:
echo ee | tee /dev/pty/2 | foo
t
没用。您可以使用 echo ee | tee $(tty) | foo
,但它仍然有一个无用的命令 (tty
),因为 /dev/tty
确实有效。
/dev/tty
是必需的 Unix 设备。您是否在 BSD 监狱中运行?tee
级联:cat some.log | tee /dev/tty | tee -a other.log | grep -i 'foo' >> foo.log
到 1) 将其全部发送到控制台,2) 将其全部附加到另一个文件中,3) 将foo
行添加到另一个文件中。