为什么管道进入BASH命令组有时会起作用?

时间:2018-04-21 16:16:45

标签: linux bash shell

我已经使用了以下命令一段时间来保持标题ps输出。

ps aux | { head -1; grep root; }

输出结果如下所示。

USER               PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root               142   0.0  0.0  1234567   2520   ??  Ss    3:14AM   0:08.03 /usr/sbin/notifyd
root                55   0.0  0.0  7890123   2460   ??  Ss    3:14AM   0:01.94 /usr/sbin/syslogd
...

但是,当与其他命令行程序一起使用时,输出不是预期的。

采用以下df示例。

df -h

输出以下内容。

Filesystem      Size  Used Avail Use% Mounted on
/dev/disk1s1    466G  103G  362G  22% /
/dev/disk1s4    466G  1.1G  362G   1% /blah/blah/blah

使用与上述示例类似的语法df ps

df -h | { head -1; grep disk1; }

输出以下内容。

Filesystem      Size  Used Avail Use% Mounted on

期望输出看起来与直接df -h命令基本相同。

为什么这与ps不同?

我觉得了解这些差异将有助于我更完整地理解BASH处理。

谢谢!

2 个答案:

答案 0 :(得分:5)

这是因为head正在缓冲其输入。它从管道读入一个大缓冲区,然后开始从该缓冲区中提取行。在读取并打印了前N行之后,它就会退出。然后grep开始从管道读取。但是head已经读入其缓冲区的任何内容都不可用。

它似乎与ps一起使用的原因是因为它产生了大量输出,这不适合这个缓冲区。然后grep能够处理输出的其余部分。但我认为如果仔细检查,你会发现结果不完整。

df的输出要小得多,它都适合head使用的缓冲区,因此grep无需处理任何内容。

缓冲区大小可能类似于4K字符。

您可以使用awk执行所需操作:

df -h | awk 'NR == 1 || /disk1/'
ps aux | awk 'NR == 1 || /root/'

NR是行号,因此如果它是第一行或与正则表达式匹配,则打印该行。

答案 1 :(得分:-1)

在这种情况下,Sed(1)也可用于过滤输出:

    ps aux | sed -n '1p; /root/p'

-n:在对所有命令应用之后,不要将输入行回显到标准输出。

1p; "地址" line1,with' p'打印图案空间

/root/p;"地址" of / regexp / matching" root",with' p'打印图案空间

替代:

    ps aux | sed '1p; /root/p; d;'

某些系统可能需要ps -aux i.t.短划线( - )到前缀选项。 Linux和* BSD系统没有(不能确定macOS的行为方式,我没有这样的系统可以检查)。