有这两个名字:a子外壳和一个子壳。
是的,子进程将通过以下任一方式启动:
sh -c 'echo "Hello"'
( echo "hello" )
echo "$(echo "hello")
echo "hello" | cat
都是等价的并且具有相同的名称吗?所有人都具有相同的属性吗?
POSIX有这个定义:
shell执行环境包括......
但上面链接的最后一段是这样的:
子 shell 环境应创建为 shell 环境的副本,但未被忽略的信号陷阱应设置为默认操作。
特别是:
命令替换、用括号分组的命令以及异步列表应在子 shell 环境中执行。此外,多命令管道中的每个命令都位于子shell环境中; ....
不sh -c 'echo "Hello"'
包含在那里,那也应该被称为子shell吗?
答案1
一个子shell重复项现有的外壳。它具有相同的变量、相同的函数、相同的选项等。在幕后,使用以下命令创建了一个子 shellfork
系统调用²;子进程继续执行预期的操作,而父进程则等待(例如,$(…)
)或继续其生命(例如,… &
)或以其他方式执行预期的操作(例如,… | …
)。
sh -c …
不创建子shell。它启动另一个程序。该程序恰好是一个 shell,但这只是一个巧合。该程序甚至可能是一个不同的 shell(例如,如果您sh -c …
从 bash 运行,并且sh
是 dash),即一个完全不同的程序,只是其行为恰好有显着的相似之处。在幕后,启动外部命令(sh
或任何其他命令)会调用fork
系统调用,然后execve
系统调用代替子进程中的 shell 程序由另一个程序执行(此处sh
)。
¹包括$$
,但不包括一些特定于 shell 的变量,例如 bash 和 mksh 的BASHPID
。
²至少,这是传统且通常的实现方式。如果 shell 能够模仿行为,那么它们就可以优化分叉。看“子shell”和“子进程”之间的确切区别是什么?
答案2
子 shell 环境不需要存在于单独的进程中,它只需要复制当前的执行环境。这ksh93
是通过virtual sub-shell
不调用fork()
.这使得 ksh93 在像 一样的古老平台上非常快Win-DOS
,而Win-DOS
分叉时却非常慢。
sh -c cmd
另一方面,使用默认 shell 创建一个新进程,该进程不需要与当前的交互式 shell 相同。
即使sh
当前 shell 相同,也不会复制执行环境,因此不会创建sub-shell
.