pep*_*via 10 bash zsh subshell
我对在子 shell 中运行命令的理解是,当前 shell 被分叉,然后子 shell 进一步执行fork所需exec的命令。
在 bash 和 zsh 中运行以下命令时,我看到奇怪的行为:
$ ( sleep 5 && sleep 6 )
在bash中运行时:
$ echo $$
6410
$ ( sleep 5 && sleep 6 )
Run Code Online (Sandbox Code Playgroud)
ps给出以下内容:
CMD:睡眠 5
PID:6590
PPID:6589
然后:
CMD:睡眠 6
PID:6616
PPID:6589
这对我来说都是有道理的。sleep 5并且sleep 6两者具有相同的父级(大概是子shell)。
但是,在zsh中,我得到以下信息:
$ echo $$
1987
$ ( sleep 5 && sleep 6 )
Run Code Online (Sandbox Code Playgroud)
ps给出以下内容:
CMD:睡眠 5
PID:7576
PPID:7575
然后:
CMD:睡眠 6
PID:7575
PPID:1987
我无法弄清楚为什么sleep 5用于运行的进程sleep 6作为其父进程,而用于运行的进程sleep 6将原始 shell 作为其父进程?
ilk*_*chu 13
你可以在 Bash 中得到类似的东西:
$ echo $$
26328
$ ( /bin/sleep 1234 )
Run Code Online (Sandbox Code Playgroud)
$ ps -o pid,ppid,stat,args -C sleep
PID PPID STAT COMMAND
26473 26328 S+ /bin/sleep 1234
Run Code Online (Sandbox Code Playgroud)
Bash 在那里所做的是,虽然它确实为子 shell 分叉了自己,但它认识到只有一个命令可以在那里运行,然后只是 exec 本身sleep作为一种优化,从而节省了额外的分叉。对于类似的东西也有同样的作用bash -c '/bin/sleep'
只是 Bash 只针对一个命令执行此操作,使用( true; /bin/sleep 2345 ),您也会看到中间 shell 进程。显然 zsh 在优化方面更加积极,并且也跳过了列表中最后一个命令的 fork。
无论如何,不要求子 shell 在另一个进程中运行。只是它运行在另一个shell 执行环境中,这是POSIX shell 语言规范中的一个短语。现在,该环境确实包括诸如umask当前工作目录之类的内容(操作系统级别上每个进程的内容)以及 shell 变量等,因此通过分叉实现单独的环境是一种简单的方法。但这不是一个要求。
例如 ksh 做了一些不同的事情,这个简单的子 shell 中根本没有分支。但它仍然有效,我们得到的值FOO是来自外壳层:
$ strace -etrace=clone,fork,vfork -f ksh -c 'FOO=out; ( FOO=in; true ); echo "$FOO"'
out
+++ exited with 0 +++
Run Code Online (Sandbox Code Playgroud)
Bash 和 zsh 会在那里分叉。ksh 也sleep作为内置实现,因此除非您显式使用,否则您不会在那里看到它的进程/bin/sleep。