Bash:内联执行返回Duplicate" Process"。为什么?

时间:2016-06-14 01:41:18

标签: linux bash

bash:4.3.42(1)-release(x86_64-pc-linux-gnu)

执行以下脚本:

# This is myscript.sh
line=$(ps aux | grep [m]yscript)  # A => returns two duplicates processes (why?)
echo "'$line'"
ps aux | grep [m]yscript          # B => returns only one

输出:

'tom   31836  0.0  0.0  17656  3132 pts/25   S+   10:33   0:00 bash myscript.sh
tom   31837  0.0  0.0  17660  1736 pts/25   S+   10:33   0:00 bash myscript.sh'
tom   31836  0.0  0.0  17660  3428 pts/25   S+   10:33   0:00 bash myscript.sh

为什么内联执行ps - 代码段(A)会返回两行?

2 个答案:

答案 0 :(得分:2)

摘要

这会创建一个子shell,因此正在运行两个进程:

line=$(ps aux | grep [m]yscript) 

这不会创建子shell。因此,myscript.sh只有一个进程正在运行:

ps aux | grep [m]yscript       

示范

让我们稍微修改一下脚本,以便将进程和子进程PID保存在变量line中:

$ cat myscript.sh 
# This is myscript.sh
line=$(ps aux | grep [m]yscript; echo $$ $BASHPID)
echo "'$line'"
ps aux | grep [m]yscript  

在bash脚本中,$$是脚本的PID,并且在子shell中保持不变。相反,当输入子shell时,bash使用子shell的PID更新$BASHPID

这是输出:

$ bash myscript.sh 
'john1024  30226  0.0  0.0  13280  2884 pts/22   S+   18:50   0:00 bash myscript.sh
john1024   30227  0.0  0.0  13284  1824 pts/22   S+   18:50   0:00 bash myscript.sh
30226 30227'
john1024   30226  0.0  0.0  13284  3196 pts/22   S+   18:50   0:00 bash myscript.sh

在这种情况下,30226是主脚本上的PID,30227是运行ps aux | grep [m]yscript的子shell的PID。

答案 1 :(得分:2)

  • 命令替换($(...)
  • 管道的每个段 [1]

导致Bash创建subshell(通过分支当前shell进程创建的子进程),然后Bash 优化子shell 如果他们导致单次调用外部实用程序

(我认为在优化方案中发生的事情是,实际创建了一个子shell,但后来通过外部实用程序的进程立即替换了exec。让我知道如果你肯定知道的话。)

应用于您的示例:

  • line=$(ps aux | grep [m]yscript)创建 3 子进程:

    • 1个子shell - 您看到的脚本分支是grep返回的其他匹配。
    • 2个子进程(每个管道段1个) - psgrep;它们取代了优化后的子壳;他们的父进程是由命令替换创建的剩余1个子shell。
  • ps aux | grep [m]yscript创建 2 子进程(每个管道段1个):

    • psgrep;它们取代了优化后的子壳;他们的父进程是当前的shell。

有关在Bash中创建子shell的场景的概述,请参阅我的this answer,但是,这不包括优化之外的场景。

[1]在Bash v4.2 +中,您可以设置选项lastpipe(默认情况下已关闭),以便在中运行 last 管道段当前的 shell而不是子shell;除了略微提高效率之外,这允许您在管道退出后当前 shell可以看到的最后一个段中声明变量。