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.grep在ps列出流程时甚至没有开始运行,那么如何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被写入以获得必须与给定模式匹配的标准输入,您将得到第一个问题的答案:
ps -ef;grep cron;ps 发送数据(甚至包含字符串"grep cron") grepgrep匹配其搜索模式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因为:
ps -ef;grep [c]ron;ps发送数据(甚至包含字符串grep [c]ron)grepgrep 与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)
在你的命令
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)
外壳构造了一系列的管道fork(),pipe()和exec()电话.根据壳体,可以首先构造它的任何部分.所以grep可能在ps开始之前就已经开始了.或者,即使ps首先启动它也将写入4k内核管道缓冲区并最终阻塞(同时打印一行过程输出),直到grep启动并开始消耗管道中的数据.在后一种情况下,如果ps能够在开始之前开始和结束,grep您可能无法grep cron在输出中看到.你可能已经注意到了这种非决定论.
| 归档时间: |
|
| 查看次数: |
6585 次 |
| 最近记录: |