我如何使用tee重定向到grep


13

我没有使用tee的丰富经验,所以我希望这不是很基本。

查看此问题的答案之一后,我遇到了一个奇怪的行为tee

为了输出第一行和找到的行,我可以使用以下命令:

ps aux | tee >(head -n1) | grep syslog
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
syslog     806  0.0  0.0  34600   824 ?        Sl   Sep07   0:00 rsyslogd -c4

但是,我第一次运行此命令(在zsh中)时,结果顺序错误,列标题位于grep结果的下方(但是,此操作不再发生),因此我尝试在以下位置交换命令:

ps aux | tee >(grep syslog) | head -n1
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

仅打印第一行,没有其他内容!我可以使用tee重定向到grep还是以错误的方式进行此操作?

当我键入此问题时,第二个命令实际上对我有用一次,我再次运行了五次,然后返回到一行结果。这就是我的系统吗?(我正在tmux中运行zsh)。

最后,为什么第一个命令没有显示“ grep syslog”结果(只有一个结果)?

为了控制,这里是不带 tee

ps aux | grep syslog
syslog     806  0.0  0.0  34600   824 ?        Sl   Sep07   0:00 rsyslogd -c4
henry    2290  0.0  0.1  95220  3092 ?        Ssl  Sep07   3:12 /usr/bin/pulseaudio --start --log-target=syslog
henry   15924  0.0  0.0   3128   824 pts/4    S+   13:44   0:00 grep syslog

更新: 似乎head导致整个命令被截断(如下面的答案所示),下面的命令现在返回以下内容:

ps aux | tee >(grep syslog) | head -n1
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
syslog     806

不是直接回答您的问题,但做类似的事情会更清洁ps aux | sed -n -e '1p' -e '/syslog/p'
jw013 2012年

我什至从未想到过sed,我认为这可能是此处相关问题的合适答案,但实际上我正在寻找有关这些命令不一致行为的信息!
Rqomey 2012年

Answers:


19
$ ps aux | tee >(head -n1) | grep syslog
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND 
syslog     806  0.0  0.0  34600   824 ?        Sl   Sep07   0:00 rsyslogd -c4

grephead在大约同一时间开始的命令,都在自己的休闲收到相同的输入数据,但通常作为数据变为可用。有一些事情可以引入“不同步”输出,使输出翻转。例如:

  1. 来自的复用数据tee实际上首先发送到一个进程,这主要取决于的实现tee。一个简单的tee实现将read有一定数量的输入,然后输入write两次:一次输入标准输出,一次输入其参数。这意味着这些目的地之一将首先获取数据。

    但是,管道均已缓冲。这些缓冲区可能每个都是1行,但是它们可能更大,这可能导致其中一个接收命令grep在另一个命令(head)接收到任何数据之前先查看其输出所需的所有内容(即ped行)。所有。

  2. 尽管如此,这些命令中的一个也有可能接收到数据,但无法及时对其进行任何处理,然后另一个命令接收到更多数据并快速对其进行处理。

    例如,即使一次将数据headgrep发送到一行,如果head不知道如何处理(或由于内核调度而延迟),grep也可以在head没有机会的情况下显示其结果。为了演示,请尝试添加延迟:ps aux | tee >(sleep 1; head -n1) | grep syslog几乎可以肯定会grep先输出。

$ ps aux | tee >(grep syslog) | head -n1
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

我相信您在这里通常只得到一行,因为head接收到第一行输入,然后关闭其stdin并退出。当tee看到其stdout已关闭时,便关闭其自己的stdin(的输出ps)并退出。这可能取决于实现。

实际上,唯一ps要发送的数据是第一行(肯定head是因为正在控制该行),并且可能还有其他几行在headteestdin描述符之前或关闭。

与第二行是否出现的不一致是由计时引起的:head关闭stdin,但ps仍在发送数据。这两个事件没有很好地同步,因此包含的行syslog仍有机会作为tee参数(grep命令)。这类似于上面的解释。

通过使用在关闭stdin / exiting之前等待所有输入的命令,可以完全避免此问题。例如,使用awk代替head,它将读取并处理其所有行(即使它们不产生任何输出):

ps aux | tee >(grep syslog) | awk 'NR == 1'

但是请注意,如上所述,这些行仍然可能会乱序显示,可以通过以下方式进行演示:

ps aux | tee >(grep syslog) | (sleep 1; awk 'NR == 1')

希望这不是太多的细节,但是有很多同时发生的事情彼此交互。单独的进程同时运行而没有任何同步,因此它们在任何特定运行上的动作都可能不同。有时,它有助于深入了解潜在过程以解释原因。


1
优秀答案!我之所以问是因为我对基本流程感兴趣。当事情变得不稳定时,我会觉得很有趣。是否有一种更好的方法ps aux | tee >(grep syslog) | head -n1可以停止head关闭stdout。哇,该命令现在已经开始提供输出,但是正如您的回答USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND syslog 806
所言

1
您可以使用不会关闭stdin的东西代替head。我已使用以下示例更新了答案:ps aux | tee >(grep syslog) | awk 'NR == 1'
mrb 2012年

1
@KrzysztofAdamski,当您使用时>(cmd),shell将创建一个命名管道并将其作为参数传递给命令(tee)。然后tee正在写到stdout(通过管道传输到awk)以及该参数。它与mkfifo a_fifo ; grep ... a_fifo一个外壳和ps | tee a_fifo | awk ...另一个外壳中的相同。
mrb 2012年

1
@ KrzysztofAdamskignu.org / software/ bash / manual/ html_node/… — Try echo >(exit 0),它将回显shell传递的实际参数(在我的情况下,它变为/dev/fd/63)。这在bash和zsh上应该相同。
mrb 2012年

1
@mrb:这是我以前不知道的非常有趣的功能,谢谢。它在bash中以某种奇怪的方式工作,但是请参见pastebin.com/xFgRcJdF。不幸的是,我现在没有时间进行调查,但是明天我会做。
Krzysztof Adamski 2012年

2

grep syslog并非始终显示,因为它取决于时间。使用外壳管道时,几乎同时运行命令。但是,这里的关键是“几乎”一词。如果ps在grep启动之前完成了所有进程的扫描,则它将不在列表中。您可以根据系统的负载等获得随机结果。

T恤也会发生类似的情况。它在subshel​​l中的后台运行,并且可能在grep之前或之后触发。这就是输出顺序不一致的原因。

至于发球区问题,它的行为很奇怪。这是因为未按正常方式使用它。它运行时没有任何参数,这意味着它应该只将数据从其stdin复制到stdout。但是它的stdout重定向到subshel​​l运行头(在第一种情况下)或grep(第二种情况)。但是它也通过管道传递给下一个命令。我认为在这种情况下发生的事情实际上取决于实现。例如,在我的bash 4.2.28上,没有任何内容写入subshel​​l stdin。在zsh上,每次尝试时,它都能以您想要的方式(打印ps的第一行和搜索的行)可靠地运行,


无论如何,这解释了一件事情,我很惊讶tee会严重延迟grep的运行!
Rqomey 2012年

0

有点黑,但这是我的解决方案,以psgrep()我使用的shell函数形式:

ps标题行重定向到STDERR,然后grep在上重定向STDOUT,但首先删除grep命令本身,以避免源于grep自身的“噪声”行:

psgrep() { ps aux | tee >(head -1>&2) | grep -v " grep $@" | grep "$@" -i --color=auto; }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.