众所周知,在花括号之间放置一个命令列表会导致列表在当前shell上下文中执行。没有创建子shell。但是当使用"&"在" {}"之后,为什么会创建两个子壳? pid 1002和1003。
{
./a.out
} &
sleep 19
使用" ./ a.out&"时,只创建一个子shell。 pid 17358。
./a.out &
sleep 19
为什么?
答案 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进程。