我有一个./scr
剧本。
abc@~ $ cat scr
#!/bin/bash
ps
echo '-------'
echo "$(ps)"
abc@~ $
我的目标是找出子流程是如何创建的。据我所知,该$(...)
部分应该创建一个子外壳,从而创建一个新进程。所以第二次调用的进程数ps
应该更大一些。
如果我在当前 shell 中获取脚本,情况就是这样:
abc@~ $ . scr
PID TTY TIME CMD
1659 ttys000 0:00.17 -bash
-------
PID TTY TIME CMD
1659 ttys000 0:00.17 -bash
1785 ttys000 0:00.00 -bash
abc@~ $
但是,在解释 shell 中启动时,进程数没有差异:
abc@~ $ ./scr
PID TTY TIME CMD
1659 ttys000 0:00.17 -bash
1790 ttys000 0:00.00 /bin/bash ./scr
-------
PID TTY TIME CMD
1659 ttys000 0:00.17 -bash
1790 ttys000 0:00.00 /bin/bash ./scr
abc@~ $
为什么会这样呢?
同样,为什么ps
给出与 相同的输出(ps)
?
abc@~ $ ps
PID TTY TIME CMD
1659 ttys000 0:00.18 -bash
abc@~ $ (ps)
PID TTY TIME CMD
1659 ttys000 0:00.18 -bash
abc@~ $
有趣的是,在命令前面添加任何其他命令会强制它“生成”预期的新进程(也在ps
顶部的脚本中生成预期的进程)。./scr
abc@~ $ (echo 1; ps)
1
PID TTY TIME CMD
1659 ttys000 0:00.20 -bash
1823 ttys000 0:00.00 -bash
abc@~ $
(ps)
外壳是否以某种方式“优化”了?为什么在来源时不是这样?
旁注:该系统实际上是 macOS,但我不认为它在这种情况下会有不同的行为。
编辑:
如在这个答案,子 shell 似乎需要优化,因此不会在单独的、新启动的 shell 中运行,因为显然不需要它。
为什么在当前shell中运行时需要它,那么( . scr
)?
答案1
命令替换发生在“子shell环境",不一定是成熟的子 shell;如果没有子 shell 环境也能达到效果,那么 shell 将避免创建无用的进程。如果你想看到一个成熟的子 shell,请给它一些需要做的事情一个完整的子外壳比较:
$ echo "$(ps fax)"
PID TTY STAT TIME COMMAND
...
1317 ? Ss 0:00 /usr/sbin/sshd -D
1751 ? Ss 0:00 \_ sshd: alexp [priv]
1788 ? S 0:00 \_ sshd: alexp@pts/0
1789 pts/0 Ss+ 0:00 \_ -bash
1822 pts/0 R+ 0:00 \_ ps fax
...
$ echo "$(ps fax; echo)"
PID TTY STAT TIME COMMAND
...
1317 ? Ss 0:00 /usr/sbin/sshd -D
1751 ? Ss 0:00 \_ sshd: alexp [priv]
1788 ? S 0:00 \_ sshd: alexp@pts/0
1789 pts/0 Ss+ 0:00 \_ -bash
1823 pts/0 S+ 0:00 \_ -bash
1824 pts/0 R+ 0:00 \_ ps fax
...