ps 问题
<h2>ps 问题</h2>
<p>新建测试脚本,名称为 test3.sh,进行如下测试:</p>
<pre><code class="language-shell">#!/bin/bash
ps auxf | grep test3.sh</code></pre>
<p>对于上面方式,主进程为 test3.sh,它会依次 clone 出 2 个子进程并发执行。子进程在稍后会调用 execve 依次将自身替换为 ps 和 grep,但在替换前,子进程是和父进程同名的。</p>
<p>由于 2 个子进程是并发执行的,所以在 ps 子进程替换后执行遍历进程时,就存在 2 种可能:</p>
<ul>
<li>
<p>如果 grep 对应的子进程还没有完成替换,此时它的子进程名和父进程是一样的,即是 test3.sh</p>
</li>
<li>如果已经完成替换,此时子进程的名称就是 grep</li>
</ul>
<p>> 注意:在比较极端的情况下,grep 对应的子进程甚至还没有来得及创建(或者创建的 pid 号比较小),而 ps 子进程已经替换并执行,此时则根本看不到第 2 个子进程。</p>
<p>结果如下:</p>
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=5f564ec60a36e1804696a0a925cbea62&amp;file=file.png" alt="" /></p>
<p>再将脚本内容改为以下:</p>
<pre><code class="language-shell">#!/bin/bash
PSLIST=`ps auxf | grep test3.sh`
echo &quot;${PSLIST}&quot;</code></pre>
<p>结果如下:</p>
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=249794477a0cd5ccdc852e01930daa51&amp;file=file.png" alt="" /></p>
<p>这种获取命令输出结果的情况,稍微有些复杂:</p>
<ul>
<li>
<p>如果只有一个命令,则直接起一个子进程,通过 pipe 管道来获取输出</p>
</li>
<li>如果涉及通过管道连接多个命令,则会新建一个单独的子进程(如图中 7442),再由此子进程再拉 ps 和 grep 进程。</li>
</ul>
<p>具体可以看下面的常见情况测试总结如下(建议大家用 strace 跟一下流程或看 bash 源码。注意:子进程都是并发执行的):</p>
<pre><code class="language-shell"># 没有 pipe,直接起 1 个子进程
ps
# 有 1 个 pipe,并起 2 个子进程
ps | grep xxx
# 有 2 个 pipe,并起 3 个子进程
ps | grep xxx | grep -v xxx
# 有 1 个 pipe,起 1 个子进程
a=`ps`
# 有 2 个 pipe,并起 3 个子进程(有个专门的子进程来起 ps, grep 子进程)
a=`ps | grep xxx`
# 有 3 个 pipe,并起 4 个子进程(同上)
a=`ps | grep xxx | grep -v xxx`</code></pre>