5

假设我有一个输出的程序:

abcd
l33t
1234

我将用printf 'abcd\nl33t\n1234\n'. 我想同时将此输出提供给两个程序。我的想法是使用tee. 假设我想将输出的副本提供给grep

printf 'abcd\nl33t\n1234\n' | tee >(grep '[a-z]' >&2) | grep '[0-9]'

我使用 Bash 4.1.2(Linux,CentOS 6.5)得到以下信息,这很好:

l33t
1234
abcd
l33t

但是如果进程替换没有重定向到stderr(即没有>&2),像这样:

printf 'abcd\nl33t\n1234\n' | tee >(grep '[a-z]') | grep '[0-9]'

然后我得到:

l33t
1234
l33t

这就像来自进程替换的标准输出(第一个 grep)被管道(第二个 grep)之后的进程使用。除了第二个 grep 已经在自己阅读内容,所以我想它不应该考虑第一个 grep 中的内容。除非我弄错了(我肯定是这样)。

我错过了什么?

4

2 回答 2

3

解释

就命令行而言,进程替换只是制作特殊文件名的一种方式。(另见文档。)所以第二个管道实际上看起来像:

printf 'abcd\nl33t\n1234\n' | tee /dev/fd/nn | grep '[0-9]'

nn一些文件描述符编号在哪里。的全部输出printf转到/dev/fd/nn,也转到grep '[0-9]'。因此,仅打印数值。

至于 内部的进程>(),它继承了其父级的标准输出。在这种情况下,该标准输出在管道内。因此, 的输出grep '[a-z]'就像 的标准输出一样通过管道tee。结果,整个管道仅通过包含数字的行。

当您改为写入 stderr ( >&2) 时,您将绕过最后一个管道阶段。因此,grep '[a-z]'on stderr 的输出将发送到终端。

一个修复

要在不使用 stderr 的情况下解决此问题,您可以为屏幕使用另一个别名。例如:

printf 'abcd\nl33t\n1234\n' | tee >(grep '[a-z]' >/dev/tty ) | grep '[0-9]'
                                               # ^^^^^^^^^

这给了我输出

l33t
1234
abcd
l33t

测试这个

为了解决这个问题,我跑了echo >(ps). 该进程是运行管道 的进程ps的子进程。bash

我也跑了

printf 'abcd\nl33t\n1234\n' | tee >(grep '[a-z]')

最后没有| grep '[0-9]'。在我的系统上,我看到

abcd    <--- the output of the tee
l33t         ditto
1234         ditto
abcd    <--  the output of the grep '[a-z]'
l33t         ditto

所有五行都进入grep '[0-9]'.

于 2017-04-13T18:26:33.983 回答
2

之后tee你有两个流

abcd
l33t
1234

第一个 grep ( >(grep '[a-z]' >&2) 过滤掉

abcd
l33t

并将结果打印到它的(!!!) stderr - 它仍然连接到您的终端......

所以,另一个简单的演示:

printf 'abcd\nl33t\n1234\n' | tee >(grep '[a-z]' >&2) | grep '[0-9]'

这打印

l33t
1234
abcd
l33t

现在添加wc -l

printf 'abcd\nl33t\n1234\n' | tee >(grep '[a-z]' >&2) | grep '[0-9]' | wc -l 

你会得到

abcd
l33t
       2

你可以清楚地看到:

abcd
l33t

是第一个的标准错误,grep但第二个 grep 的标准输出被重定向到wc并打印

2

现在进行另一个测试:

printf 'abcd\nl33t\n1234\n' | tee >(grep '[a-z]' ) | cat -

输出

abcd
l33t
1234
abcd
l33t

例如,来自 the 的两行和来自 thegrep的完整输入print

数数:

printf 'abcd\nl33t\n1234\n' | tee >(grep '[a-z]' ) | cat - | wc -l

输出

5
于 2017-04-13T18:51:39.370 回答