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

Ank*_*wal 17 linux bash pipe ps

当我做

$ ps -ef | grep cron
Run Code Online (Sandbox Code Playgroud)

我明白了

root      1036     1  0 Jul28 ?        00:00:00 cron
abc    21025 14334  0 19:15 pts/2    00:00:00 grep --color=auto cron
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么我会看到第二行.根据我的理解,ps列出进程并将列表管道grep.grepps列出流程时甚至没有开始运行,那么如何grep在o/p中列出流程?

相关第二个问题:

当我做

$ ps -ef | grep [c]ron
Run Code Online (Sandbox Code Playgroud)

我只得到

root      1036     1  0 Jul28 ?        00:00:00 cron
Run Code Online (Sandbox Code Playgroud)

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

dAm*_*m2K 22

执行命令时:

ps -ef | grep cron
Run Code Online (Sandbox Code Playgroud)

你正在使用的shell

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

将执行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)创建的管道的读取端.

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

现在你有了两个子节点(兄弟节点)的shell进程,其中第一个是ps带有-ef属性的命令,第二个是grep带有cron属性的命令.管的读取端附接至STDIN所述的grep命令和写入侧附接至STDOUT所述的ps命令:所述的标准输出ps命令被附接到的标准输入grep命令.

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

  1. shell运行: ps -ef;
  2. shell运行: grep cron;
  3. ps 发送数据(甚至包含字符串"grep cron") grep
  4. grep匹配其搜索模式STDIN,它匹配字符串"grep cron",因为你传入的"cron"属性grep:你指示grep匹配"cron"字符串,因为"grep cron"是一个返回的字符串ps当时grep已经开始执行.

执行时:

ps -ef | grep '[c]ron'
Run Code Online (Sandbox Code Playgroud)

传递的属性指示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"的字符串

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

希望这个长期响应能够澄清shell管道过程.

小费:

ps -ef | grep cron | grep -v grep
Run Code Online (Sandbox Code Playgroud)


Gol*_*wby 8

在你的命令

ps -ef | grep 'cron'
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

ps aux | grep [c]ron
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron
Run Code Online (Sandbox Code Playgroud)

那匹配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
Run Code Online (Sandbox Code Playgroud)

如果删除C,它将无法匹配,因为"cron",以ac开头:

ps aux | grep [abedf]ron
Run Code Online (Sandbox Code Playgroud)

^没有结果

编辑2

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

ps aux | grep [c][ro][ro][n]
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron
Run Code Online (Sandbox Code Playgroud)


Ben*_*son 7

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