bash:4.3.42(1)-release(x86_64-pc-linux-gnu)
执行以下脚本:
# This is myscript.sh
line=$(ps aux | grep [m]yscript) # A => returns two duplicates processes (why?)
echo "'$line'"
ps aux | grep [m]yscript # B => returns only one
输出:
'tom 31836 0.0 0.0 17656 3132 pts/25 S+ 10:33 0:00 bash myscript.sh
tom 31837 0.0 0.0 17660 1736 pts/25 S+ 10:33 0:00 bash myscript.sh'
tom 31836 0.0 0.0 17660 3428 pts/25 S+ 10:33 0:00 bash myscript.sh
为什么内联执行ps
- 代码段(A)会返回两行?
答案 0 :(得分:2)
这会创建一个子shell,因此正在运行两个进程:
line=$(ps aux | grep [m]yscript)
这不会创建子shell。因此,myscript.sh
只有一个进程正在运行:
ps aux | grep [m]yscript
让我们稍微修改一下脚本,以便将进程和子进程PID保存在变量line
中:
$ cat myscript.sh
# This is myscript.sh
line=$(ps aux | grep [m]yscript; echo $$ $BASHPID)
echo "'$line'"
ps aux | grep [m]yscript
在bash脚本中,$$
是脚本的PID,并且在子shell中保持不变。相反,当输入子shell时,bash使用子shell的PID更新$BASHPID
。
这是输出:
$ bash myscript.sh
'john1024 30226 0.0 0.0 13280 2884 pts/22 S+ 18:50 0:00 bash myscript.sh
john1024 30227 0.0 0.0 13284 1824 pts/22 S+ 18:50 0:00 bash myscript.sh
30226 30227'
john1024 30226 0.0 0.0 13284 3196 pts/22 S+ 18:50 0:00 bash myscript.sh
在这种情况下,30226是主脚本上的PID,30227是运行ps aux | grep [m]yscript
的子shell的PID。
答案 1 :(得分:2)
$(...)
)导致Bash创建subshell(通过分支当前shell进程创建的子进程),然后Bash 优化子shell 如果他们导致单次调用外部实用程序。
(我认为在优化方案中发生的事情是,实际创建了一个子shell,但后来通过外部实用程序的进程立即替换了exec
。让我知道如果你肯定知道的话。)
应用于您的示例:
line=$(ps aux | grep [m]yscript)
创建 3 子进程:
grep
返回的其他匹配。ps
和grep
;它们取代了优化后的子壳;他们的父进程是由命令替换创建的剩余1个子shell。 ps aux | grep [m]yscript
创建 2 子进程(每个管道段1个):
ps
和grep
;它们取代了优化后的子壳;他们的父进程是当前的shell。有关在Bash中创建子shell的场景的概述,请参阅我的this answer,但是,这不包括优化之外的场景。
[1]在Bash v4.2 +中,您可以设置选项lastpipe
(默认情况下已关闭),以便在中运行 last 管道段当前的 shell而不是子shell;除了略微提高效率之外,这允许您在管道退出后当前 shell可以看到的最后一个段中声明变量。