bash -c何时创建子shell?CentOS7.4下命令差异原因咨询
关于
bash -c子shell创建的两个问题解答 1. 执行bash -c命令时,何时会创建子shell?
首先要明确:bash -c <command>本身就会启动一个新的bash进程——这就是一个子shell,相对于调用它的父shell(比如你的登录bash)。但在不同场景下,这个子shell的存在形式会有差异:
- 当
<command>是单个简单命令(没有管道|、逻辑运算符&&/||、分号;、括号()等控制结构)时,bash -c启动的子shell会做一个优化:它会调用exec()系统调用把自己直接替换成目标命令,不会保留bash进程。这时候你在进程树里只会看到目标命令,看不到中间的bash子shell。 - 当
<command>是复合命令(包含多个命令串联、管道、条件判断、循环等需要shell解析控制流程的结构)时,子shell无法直接替换自己——因为它需要先解析执行流程,依次处理多个命令,或者根据前一个命令的结果决定后续操作。这时候子shell会保留自身进程,然后fork子进程来执行每个具体命令,所以进程树中会看到这个bash子shell的存在。
2. 为什么第二个命令会多创建一个子shell?
结合你的CentOS服务器上的进程树来看:
- 第一个命令:
bash -c "python -m SimpleHTTPServer"
这是单个简单命令,所以bash -c启动的子shell直接用exec替换成了python进程,进程树里登录bash(11598)直接作为python的父进程,看不到中间的bash子shell。 - 第二个命令:
bash -c "python -V && python -m SimpleHTTPServer"
这是用&&连接的复合命令——shell需要先执行python -V,检查它的退出码是否为0,再决定是否执行后面的python -m SimpleHTTPServer。这种情况下,bash -c启动的子shell(11638)无法直接替换自己,必须保留自身来处理这个逻辑判断流程。它会先fork一个子进程执行python -V(执行完就退出,所以pstree里没显示),然后再fork子进程执行python -m SimpleHTTPServer,所以进程树里会看到这个中间的bash子shell(11638),它作为python(11640)的父进程,而它的父是你的登录bash(11598)。
简单总结:复合命令需要shell来管理执行流程,所以bash -c的子shell必须保留;简单命令可以直接替换,所以子shell会被目标命令取代,不留痕迹。
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

