Subshel​​l不会创建单独的进程

Subshel​​l不会创建单独的进程

我有一个./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
  ...

相关内容