为什么shell命令“{command1; command2:}&"打开子壳?

时间:2016-05-14 10:08:49

标签: linux bash shell subshell

众所周知,在花括号之间放置一个命令列表会导致列表在当前shell上下文中执行。没有创建子shell。但是当使用"&"在" {}"之后,为什么会创建两个子壳? pid 1002和1003。

{
    ./a.out
} &

sleep 19

enter image description here

使用" ./ a.out&"时,只创建一个子shell。 pid 17358。

./a.out &
sleep 19

enter image description here

为什么?

2 个答案:

答案 0 :(得分:4)

如果命令被控制操作符&终止,则shell执行后台(或异步)中的命令(或{...}中包含的命令列表) 子shell

shell不等待命令完成,返回状态为0。

在C程序中,通过执行fork()后跟execvp()系统调用来完成。

更新:根据以下评论和更新的问题。这是正在发生的事情。

当你跑步时:

./a.out &

BASH直接在后台运行a.out,因为运行二进制文件a.out并不需要单独的shell进程。

当你跑步时:

{ ./a.out; } &

BASH必须首先分叉并创建一个子shell,因为在{...}中可以有一系列命令,然后新分叉的子shell在一个单独的进程中运行a.out。所以BASH并没有为此创造2个子壳。只创建了一个子shell,第二个pid是a.out

答案 1 :(得分:4)

列表的后台执行使用子shell,因为某些东西需要等待该列表的每个成员并运行下一个成员。列表背景化后,父shell需要可用于新命令;它也无法管理后台列表。 bash一次不能做多件事。因此,为了使后台列表工作,它运行一个子shell。

请注意,您可以拒绝后台列表,它将继续运行,表明子shell正在执行其工作:

$ {
> sleep 1; sleep 2; sleep 3; sleep 4; sleep 5
> } &
$ disown
$ ps -f | grep sleep
dave     31845 31842  0 03:50 pts/1    00:00:00 sleep 3 
dave     31849 31771  0 03:50 pts/1    00:00:00 grep sleep

您甚至可以注销,子shell将继续运行列表中的进程。

当你设置单个命令时,不需要子shell,因为shell在运行命令后没有其他工作要做。

在您的示例中,第二个附加bash子进程PID 1002似乎是您正在执行的脚本。这与列表背景机制无关(概念上至少);单独文件中的任何脚本都有自己的bash进程。