为什么(ps -f)不创建子shell但只创建一个单独的进程?

时间:2014-09-05 15:49:59

标签: linux shell unix

我需要一些帮助,因为我没有得到任何东西。根据我从Internet上读到的内容,当我们执行shell脚本或者在括号中运行命令时会创建一个子shell:( )

我尝试使用仅包含以下命令的脚本来测试它:

ps -f

当我运行它时,我看到以下结果:

ID      PID  PPID  C STIME TTY          TIME CMD 
me     2213  2160  0 08:53 pts/14   00:00:00 bash 
me     3832  2213  0 18:41 pts/14   00:00:00 bash 
me     3833  3832  0 18:41 pts/14   00:00:00 ps -f

哪个好,因为我看到我的bash进程为我的脚本产生了另一个bash进程。

但是当我这样做时:

( ps -f )

它产生:

UID     PID  PPID  C STIME TTY          TIME CMD 
me     2213  2160  0 08:53 pts/14   00:00:00 bash 
me     3840  2213  0 18:46 pts/14   00:00:00 ps -f

因此,如果括号产生子shell,为什么它不会显示在进程中?为什么ps -f被视为另一个过程?每个命令都作为一个单独的进程运行吗?

2 个答案:

答案 0 :(得分:4)

看起来你已经抓住了bash进行了一些优化。如果一个子shell只包含一个命令,为什么要真正使它成为子shell?

$ ( ps -f )
UID        PID  PPID  C STIME TTY          TIME CMD
jovalko  29393 24133  0 12:05 pts/10   00:00:00 bash
jovalko  29555 29393  0 12:07 pts/10   00:00:00 ps -f

但是,添加第二个命令,比如:(bash null命令,什么都不做),这就是结果:

$ ( ps -f ; : )
UID        PID  PPID  C STIME TTY          TIME CMD
jovalko  29393 24133  0 12:05 pts/10   00:00:00 bash
jovalko  29565 29393  0 12:08 pts/10   00:00:00 bash
jovalko  29566 29565  0 12:08 pts/10   00:00:00 ps -f

使用子shell的主要原因之一是您可以对一组命令执行I / O重定向等操作,而不是单个命令,但如果您的子shell只包含一个命令,则没有太多理由真正分叉新的bash流程首先。

至于ps作为一个过程计算,它会有所不同。您使用的许多命令如lsgrepawk都是外部程序。但是,也有像cdkill这样的内置组件。

您可以使用bash命令确定type中的命令:

$ type ps
ps is hashed (/bin/ps)
$ type cd
cd is a shell builtin

答案 1 :(得分:1)

问题的主要部分是:

  

每个命令都作为一个单独的进程运行吗?

YES!每个命令都没有内置到bash中(如declare等),作为单独的进程运行。它是如何工作的?

当你输入ps然后按回车键时,bash会分析你输入的内容,做通常的事情,如全局,变量扩展等等,最后当它是外部命令时

  • bash forks本身。

分叉意味着,在分叉之后立即,你将两个 相同 {{1}进程(每个进程ID具有不同的进程ID(PID)) - 称为" parent"和"孩子",这两个正在运行的bash程序之间的唯一区别是,"父母"获取(从bash返回值)孩子的PID,但孩子不知道父母的PID。 (孩子的叉子返回0)。

  • 在fork之后,(bash以这种方式编写) - 子用新的程序图像替换自己(例如:fork) - 使用ps调用。
  • 在此之后,孩子bash当然不再存在,只运行新执行的命令 - 例如exec

当然,当bash转向fork时,还要做很多其他事情,比如I / O重定向,打开 - 关闭文件句柄,改变孩子的信号处理以及许多其他事情。