【问题标题】:About shell and subshell关于外壳和子外壳
【发布时间】:2012-05-30 21:12:35
【问题描述】:

我是shell新手,刚知道use(command)会创建一个新的子shell并执行命令,所以我尝试打印父shell和子shell的pid:

#!/bin/bash

echo $$
echo "`echo $$`"
sleep 4
var=$(echo $$;sleep 4)
echo $var

但答案是:

$./test.sh
9098
9098
9098

我的问题是:

  1. 为什么只有三个回声打印?我的代码中有 4 个回显。
  2. 为什么三个 pid 相同? subshel​​l 的 pid 显然和他父亲的不一样。

非常感谢您的回答:)

【问题讨论】:

    标签: linux bash shell


    【解决方案1】:

    首先,赋值捕获子节点的标准输出并将其放入var,而不是打印出来:

    var=$(echo $$;sleep 4)
    

    这可以通过以下方式看到:

    $ xyzzy=$(echo hello)
    $ echo $xyzzy
    hello
    

    其次,所有这些$$ 变量都在 current shell 中进行评估,这意味着它们在任何子项启动之前变成了当前 PID。孩子们看到已经生成的PID。换句话说,孩子们正在执行echo 9098,而不是echo $$

    如果你想要孩子的PID,你必须防止在父母中翻译,例如使用单引号:

    bash -c 'echo $$'
    

    【讨论】:

    • 如果您咨询“man bash”,paxdiablo 的答案中的信息可在标题命令替换和特殊参数下找到。
    • 我要补充两点:1. 代码中有 5 个回显,其中两个被捕获为字符串(一个立即回显,另一个存储在变量)。 2、在bash 4.0及更高版本中,环境变量“$BASHPID”会打印出子shell的PID。 Bash 4.0 还不常见,试试 bash --version 看看你的。
    【解决方案2】:
    echo "one.sh $$"
    echo `eval echo '$$'`
    

    我希望以上内容可以打印不同的 pid,但事实并非如此。它正在创建一个子进程。通过在 `` 中添加 sleep 进行验证。

    echo "one.sh $$"
    echo `eval "echo '$$'";sleep 10`
    

    从脚本执行上述操作并运行 ps 会显示两个进程 one.sh(脚本名称)和 sleep。

    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    test    12685  0.0  0.0   8720  1012 pts/15   S+   13:50   0:00      \_ bash one.sh
    test    12686  0.0  0.0   8720   604 pts/15   S+   13:50   0:00          \_ bash one.sh
    test    12687  0.0  0.0   3804   452 pts/15   S+   13:50   0:00              \_ sleep 10
    

    这是产生的输出

    one.sh 12685
    12685
    

    不知道我错过了什么。

    【讨论】:

    • Bash 是鬼鬼祟祟的,它决定$$ 在启动时扩展为什么,然后将其保存在它派生的所有子shell 中。 (据我所知,这是有意使扩展保持不变,例如,用于命名临时文件。)
    【解决方案3】:

    解决方案是$!。如:

    #!/bin/bash
    
    echo "parent" $$
    yes > /dev/null &
    echo "child" $!
    

    输出:

    $ ./prueba.sh
    parent 30207
    child 30209
    

    【讨论】: