我对在子shell中运行命令的理解是,当前的shell是分叉的,然后子shell对所需的命令执行进一步的fork和exec。
在bash和zsh中运行以下代码时,我看到了奇怪的行为:$ ( sleep 5 && sleep 6 )
在<>bash中运行时:
$ echo $
6410
$ ( sleep 5 && sleep 6 )ps给出了以下内容: CMD:睡眠5个PID:6590 PPID:6589
然后: CMD:睡眠6 PID:6616 PPID:6589
这一切对我来说都是有意义的。sleep 5和sleep 6都有相同的父级(可能是子subshell)。
但是,在<>zsh中,我得到以下内容:
$ echo $
1987
$ ( sleep 5 && sleep 6 )ps给出了以下内容: CMD:睡眠5个PID:7576 PPID:7575
然后: CMD:睡眠6 PID:7575 PPID:1987
我无法解释为什么sleep 5将用于运行sleep 6的进程作为其父进程,而用于运行sleep 6的进程以原始shell作为其父进程?
发布于 2022-05-08 13:37:22
你可以在Bash得到类似的东西:
$ echo $
26328
$ ( /bin/sleep 1234 )$ ps -o pid,ppid,stat,args -C sleep
PID PPID STAT COMMAND
26473 26328 S+ /bin/sleep 1234Bash在那里所做的是,虽然它为子subshell做了分叉,但它认识到只有一个命令要在那里运行,然后只需要执行sleep作为一个优化,从而节省额外的分叉。它对像bash -c '/bin/sleep'这样的东西也是一样的
只是Bash只在一个命令的情况下才这样做,使用( true; /bin/sleep 2345 ),您也会看到中间的shell进程。显然,zsh在优化方面更具侵略性,也跳过了列表的最后一个命令的叉。
无论如何,不需要在另一个进程中运行子there。只是它运行在另一个shell执行环境中,这是来自POSIX壳语言规范的一个短语。现在,该环境确实包括了诸如umask和当前工作目录( OS级别上的每个进程)以及shell变量等内容,因此通过分叉实现单独的环境是一种简单的方法。但这不是要求。
例如,ksh做了一些不同的事情,在这个简单的子subshell中根本没有分叉。但是它仍然有效,我们得到的FOO值是从外壳级别得到的:
$ strace -etrace=clone,fork,vfork -f ksh -c 'FOO=out; ( FOO=in; true ); echo "$FOO"'
out
+++ exited with 0 +++巴什和兹什会在那里分叉。另外,ksh将sleep实现为内置的,因此除非您显式地使用/bin/sleep,否则您将不会在那里看到它的进程。
https://unix.stackexchange.com/questions/701831
复制相似问题