为什么ps o / p在管道之后列出grep进程?

时间:2011-08-01 02:21:11

标签: linux bash pipe ps

当我这样做时

$ ps -ef | grep cron

我得到了

root      1036     1  0 Jul28 ?        00:00:00 cron
abc    21025 14334  0 19:15 pts/2    00:00:00 grep --color=auto cron

我的问题是为什么我会看到第二行。根据我的理解,ps列出了进程并将列表传递给grep。在grep列出流程时,ps甚至尚未开始投放,那么o / p中是如何列出grep进程的呢?

相关的第二个问题:

当我这样做时

$ ps -ef | grep [c]ron

我只得到

root      1036     1  0 Jul28 ?        00:00:00 cron

第一次和第二次grep执行之间有什么区别?

7 个答案:

答案 0 :(得分:21)

执行命令时:

ps -ef | grep cron

您正在使用的shell

(...我假设bash在你的情况下,由于grep的颜色属性我认为你正在运行像linux发行版的gnu系统,但它在其他unix / shell上也是一样的......)< / p>

将执行pipe()调用以创建FIFO,然后它将fork()(制作自身的运行副本)。这将创建一个新的子进程。这个新生成的子进程将close()其标准输出文件描述符(fd 1),并将fd 1附加到父进程(执行命令的shell)创建的管道的写入侧。这是可能的,因为fork()系统调用将为每个系统维护一个有效的打开文件描述符(在本例中为管道fd)。执行此操作后,exec()环境变量中的第一个(在您的情况下)ps命令将PATH。通过exec()调用,该过程将成为您执行的命令。

因此,您现在拥有一个带有子项的shell进程,在您的情况下,具有ps属性的-ef命令。

此时,父(shell)fork()再次出现。这个新生成的子进程close()是其标准输入文件描述符(fd 0),并将fd 0附加到父进程(执行命令的shell)创建的管道的读取端。

执行此操作后,它将exec()在PATH环境变量中找到的第一个(在您的情况下)grep命令。

现在你有一个带有两个子节点(兄弟节点)的shell进程,其中第一个是具有ps属性的-ef命令,第二个是带有grep命令的cron命令。 STDIN属性。管道的读取端附加到grep命令的STDOUT,写入端附加到ps命令的ps:标准输出grep命令附加到ps命令的标准输入。

由于ps -ef;被编写为在每个正在运行的进程上发送标准输出信息,而grep被写入以获得必须与给定模式匹配的标准输入,您将得到答案第一个问题:

  1. shell运行:grep cron;
  2. shell运行:ps
  3. grep将数据(甚至包含字符串“grep cron”)发送到grep
  4. STDINgrep的搜索模式匹配,并且匹配字符串“grep cron”,因为您传递给grep的“cron”属性:您正在指示{{ 1}}匹配“cron”字符串,因为“grep cron”是psgrep开始执行时返回的字符串。
  5. 执行时:

    ps -ef | grep '[c]ron'
    

    传递的属性指示grep匹配包含“c”后跟“ron”的内容。与第一个示例类似,但在这种情况下,它会破坏ps返回的匹配字符串,因为:

    1. shell运行:ps -ef;
    2. shell运行:grep [c]ron;
    3. ps将数据(甚至包含字符串grep [c]ron)发送到grep
    4. grep与stdin的搜索模式不匹配,因为找不到包含“c”后跟“ron”的字符串,但它找到了一个包含“c”后跟“] ron”的字符串< / LI>

      GNU grep没有任何字符串匹配限制,并且在某些平台上(我认为Solaris,HPUX,aix)字符串的限制由“$ COLUMN”变量或终端的屏幕宽度给出

      希望这个长时间的响应能够澄清shell管道过程。

      提示:

      ps -ef | grep cron | grep -v grep
      

答案 1 :(得分:8)

在你的命令中

ps -ef | grep 'cron'

Linux正在ps -ef命令之前执行“grep”命令。然后,Linux将“ps -ef”的标准输出(STDOUT)映射到grep命令的标准输入(STDIN)。

它不执行ps命令,将结果存储在内存中,然后将它传递给grep。想一想,为什么会这样呢?想象一下,如果你正在管理一百GB的数据?

编辑关于您的第二个问题:

在grep(和大多数正则表达式引擎)中,您可以指定括号,让它知道您将在括号中接受任何字符。所以写[c]意味着它会接受任何字符,但只指定了c。同样,你可以做任何其他角色组合。

ps aux | grep cron
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron
root     23744  0.0  0.0  14564   900 pts/0    S+   21:13   0:00 grep --color=auto cron

^匹配自己,因为你自己的命令包含“cron”

ps aux | grep [c]ron
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron

匹配cron,因为cron包含c,然后是“ron”。但它与您的请求不符,因为您的请求是[c] ron

只要包含c:

,您可以在括号中放置任何内容
ps aux | grep [cbcdefadq]ron
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron

如果删除C,它将无法匹配,因为“cron”以c开头:

ps aux | grep [abedf]ron

^没有结果

修改2

重申一点,你可以用grep做各种疯狂的事情。选择第一个角色是没有意义的。

ps aux | grep [c][ro][ro][n]
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron

答案 2 :(得分:7)

shell通过一系列fork()pipe()exec()调用构建您的管道。根据壳体,可以首先构造它的任何部分。因此,在grep开始之前,ps可能已经在运行。或者,即使ps首先启动它也会写入4k内核管道缓冲区并最终阻塞(同时打印一行进程输出),直到grep启动并开始使用管道中的数据。在后一种情况下,如果ps能够在grep开始之前开始和结束,您可能无法在输出中看到grep cron。你可能已经注意到了这种非决定论。

答案 3 :(得分:2)

您写道:“根据我的理解,ps列出了进程并将列表管道为grep。当ps列出进程时,grep甚至还没有开始运行”。

您的理解不正确。

这不是管道的工作原理。 shell执行运行第一个命令完成,记住第一个命令的输出,然后然后使用该数据作为输入运行下一个命令。不会。两个进程都执行,其输入/输出已连接。正如Ben Jackson写的那样,没有什么可以特别保证进程同时运行,如果它们都是非常短暂的,并且内核可以轻松地管理通过连接的少量数据。在这种情况下,它确实可能以您期望的方式发生,只是偶然。但要记住的概念模型是它们并行运行。

如果你想要官方消息来源,请参阅bash手册页:

  A pipeline is a sequence of one or more commands separated by the character |.  The format for a pipeline is:

         [time [-p]] [ ! ] command [ | command2 ... ]

  The  standard  output  of command is connected via a pipe to the standard input of command2.  This connection is
  performed before any redirections specified by the command (see REDIRECTION below).

  ...

  Each command in a pipeline is executed as a separate process (i.e., in a subshell).

关于你的第二个问题(完全没有关系,我很遗憾地说),你只是描述了正则表达式如何工作的特性。正则表达式cron与字符串cron匹配。正则表达式[c]ron使匹配字符串[c]ron。因此,第一个grep命令将在进程列表中找到它,但第二个命令不会。

答案 4 :(得分:1)

其他人已经回答了您的实际问题,但我会提供一个提示:如果您不想看到列出的grep进程,可以这样做:

$ ps -ef | grep [c]ron

答案 5 :(得分:0)

pgrep有时优于ps -ef | grep word,因为它排除了grep。尝试

pgrep -f bash
pgrep -lf bash

答案 6 :(得分:-1)

$ ps -ef | grep cron

Linux Shell始终从右到左执行命令。所以,在ps -ef执行之前grep cron已经执行了这就是为什么o / p显示命令本身。

$ ps -ef | grep [c]ron

但是在这个你指定的grep ron后面只有c。所以,o / p没有命令行,因为在命令中有[c] ron。