为什么ps o / p列出pipe道后的grep进程?

当我做

$ 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列出的进程和pipe道列表grepgrep甚至没有开始运行,而ps正在列出进程,那么如何将grep进程列在o / p?

相关第二个问题:

当我做

 $ ps -ef | grep [c]ron 

我只得到

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

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

Solutions Collecting From Web of "为什么ps o / p列出pipe道后的grep进程?"

当你执行命令时:

 ps -ef | grep cron 

你正在使用的外壳

(…我认为你的情况bash,由于grep的颜色属性,我认为你正在运行一个GNU系统像一个Linux发行版,但在其他Unix /壳也是一样的…)

将执行pipe()调用来创建一个FIFO,然后fork() (自己创建一个正在运行的副本)。 这将创建一个新的子进程。 这个新生成的子进程将close()其标准输出文件描述符(fd 1),并将fd 1附加到父进程(执行该命令的shell)创建的管道的写入端。 这是可能的,因为fork()系统调用将为每个维护有效的打开文件描述符(在这种情况下为管道fd)。 这样做后,将exec()第一个(在你的情况下) ps命令找到你的PATH环境变量。 用exec()调用的过程将成为你执行的命令。

所以,你现在有一个子进程的shell进程,在你的情况下,带有-ef属性的ps命令。

在这一点上,父亲(壳) fork()再次。 这个新生成的子进程close()是其标准输入文件描述符(fd 0),并将fd 0附加到由父进程(执行该命令的shell所创建的管道的读取侧)。

这样做后,将exec()您的PATH环境变量中找到第一个(在你的情况下) grep命令。

现在你有两个孩子(兄弟姐妹)的shell进程,其中第一个是带有-ef属性的ps命令,第二个是带有cron属性的grep命令。 管道的读取端连接到grep命令的STDIN ,写入端连接到ps命令的STDOUTps命令的标准输出连接到grep命令的标准输入。

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

  1. shell运行: ps -ef;
  2. shell运行: grep cron;
  3. ps发送数据(甚至包含字符串“grep cron”)到grep
  4. grepSTDIN中的搜索模式相匹配,并且由于传递给grep的“cron”属性,它匹配字符串“grep cron”:您指示grep匹配“cron”字符串,因为“grep cron”是在grep开始执行时,由ps返回的字符串。

当你执行:

 ps -ef | grep '[c]ron' 

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

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

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

希望这个长时间的回应澄清了shell管道过程。

小费:

 ps -ef | grep cron | grep -v grep 

在你的命令

 ps -ef | grep 'cron' 

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

它不执行ps命令,将结果存储在内存中,并将它们传递给grep。 想想,为什么呢? 想象一下,如果你正在管理一百千兆字节的数据?

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

在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包含ac,然后是“ron”。 它不符合你的要求,因为你的请求是[c] ron

你可以把任何你想要的括号中,只要它包含c:

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

如果删除C,它将不会匹配,因为“cron”以ac开头:

 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 

shell通过一系列的fork()pipe()exec()调用来构建你的管道。 根据壳,可以首先构造它的任何部分。 所以grep可能已经在ps启动之前运行了。 或者,即使ps首先启动,它将写入一个4k内核管道缓冲区,并最终会阻塞(当打印一行过程输出时),直到grep启动并开始消耗管道中的数据。 在后一种情况下,如果ps能够在grep甚至启动之前启动并完成,您可能看不到输出中的grep cron 。 你可能已经注意到这个非确定性了。

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

 $ ps -ef | grep [c]ron 

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

你的理解是不正确的。

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

如果你想要官方消息,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 (ie, in a subshell). 

至于你的第二个问题(这个问题根本就没什么关系,我很遗憾地说),你只是描述了正则表达式是如何工作的。 正则表达式cron匹配字符串cron 。 正则表达式[c]ron与字符串[c]ron 匹配。 因此,第一个grep命令将在进程列表中找到自己,但第二个不会。

 $ ps -ef | grep cron 

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

 $ ps -ef | grep [c]ron 

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

pgrep有时比ps -ef | grep word更好 ps -ef | grep word因为它排除了grep 。 尝试

 pgrep -f bash pgrep -lf bash