Hak*_*aba 5 shell bash shell-script subshell
考虑以下两个 bash 命令。一个创建子shell,另一个不创建。
没有子外壳
$ bash -c "sleep 10000 "
Run Code Online (Sandbox Code Playgroud)
pstree 输出:
bash,100648
??sleep,103509 10000
Run Code Online (Sandbox Code Playgroud)
带子壳
$ bash -c "sleep 10000; sleep 99999 "
bash,100648
??bash,103577 -c sleep 10000; sleep 99999
??sleep,103578 10000
Run Code Online (Sandbox Code Playgroud)
这是某种优化吗?Bash 查看命令并跳过简单命令的进程创建。看起来简单的命令是由父终端的 bash 生成的。
我正在使用的 Bash 版本是
$ bash --version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Run Code Online (Sandbox Code Playgroud)
不过,我认为在 bash 3.X 中也可以观察到同样的情况。
还有一些例子。使用内置函数生成子shell。内置程序不会在父 bash 中执行。
$ bash -c "read"
bash,100648
??bash,104336 -c read
Run Code Online (Sandbox Code Playgroud)
sleep可以通过top输出重定向和输出重定向来重现相同的行为。
$ bash -c "top -b "
bash,100648
??top,104392 -b
Run Code Online (Sandbox Code Playgroud)
和
$ bash -c "top -b > /dev/null "
bash,100648
??bash,104420 -c top -b > /dev/null
??top,104421 -b
Run Code Online (Sandbox Code Playgroud)
在第一个示例中,PID 为 100648 的 shell 是您的交互式 shell,而sleep实际上是替换bash -c \'\'进程的进程。系统调用生成一个新程序,该execve()程序保留调用它的原始进程的 PID,因此您在那里看不到原始进程bash -c \'\'。简单的命令取代 shell 进程的简单原因是因为它节省了资源,正如 Stephane 的回答中所解释的那样:Why is there no suggest clone or fork in simple bash command and how it's did? 。
从一个终端的简单测试也可以看出这一点:
\n$ echo $$\n10250\n$ bash -c \'sleep 60\'\nRun Code Online (Sandbox Code Playgroud)\n在另一篇文章中:
\n$ pstree -p 10250\nbash(10250)\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80sleep(21031)\nRun Code Online (Sandbox Code Playgroud)\n至于为什么会这样,是因为只有一个简单的命令,没有管道,bash 对简单的命令直接执行execve。
正是由于这个原因,bash在第二个示例中认识到您有多个命令语句,因此sleep对于"sleep 10000; sleep 99999 ". 在第一种情况下,execve()可以只替换父进程,当新进程退出时 - 没问题。但这里 shell 在第一个命令完成后无法退出。因此,将会出现 fork 和 execve,sleep 10000这就是您在输出中看到的内容,pstree稍后会出现一个新的 fork 和 execvesleep 99999
您可以执行的另一个测试是相信简单的命令bash -c \'\'替换了 shell 进程:
$ bash -c \'grep "^Pid:" /proc/self/status /proc/$$/status\'\n/proc/self/status:Pid: 23946\n/proc/23946/status:Pid: 23946\nRun Code Online (Sandbox Code Playgroud)\n请注意,这种行为是 bash 特定的。对于/bin/dash基于 Debian 的发行版(在 中也很明显strace):
$ sh -c \'grep "^Pid:" /proc/self/status /proc/$$/status\'\n/proc/self/status:Pid: 24188\n/proc/24187/status:Pid: 24187\nRun Code Online (Sandbox Code Playgroud)\n
的输出pstree具有误导性。
bash -c "sleep 10000 "
Run Code Online (Sandbox Code Playgroud)
确实创建了一个 bash 子进程。但该进程不会创建另一个子进程。sleep因为运行shell后无需再执行任何操作,因此无需先分叉即可直接execve()进行操作sleep。
因为速度太快了,您只能看到execvein之后的结果pstree。
但在
bash -c "sleep 10000; sleep 99999 "
Run Code Online (Sandbox Code Playgroud)
case 新的 bash 分叉两次,每个命令一次。它也可以执行execve最后一个命令,而不是首先分叉。我不知道为什么没有。
这种情况和重定向情况可能只是需要分叉时的检测问题。
| 归档时间: |
|
| 查看次数: |
1324 次 |
| 最近记录: |