关于shell和子shell

3

我是shell的新手,刚学习到使用 (command) 命令将创建一个新的子shell并执行命令,因此我尝试打印父shell和子shell的pid:

#!/bin/bash

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

但是答案是:
$./test.sh
9098
9098
9098

我的问题是:

  1. 为什么只有三个echo输出?我的代码中有4个echo。
  2. 为什么这三个pid相同?子shell的pid显然与父进程不同。

非常感谢您的回答:)

3个回答

6

首先,该任务捕获子进程的标准输出并将其放入变量var中,而不是直接打印出来:

var=$(echo $$;sleep 4)

这可以通过以下方式进行查看:
$ xyzzy=$(echo hello)
$ echo $xyzzy
hello

其次,所有这些$$变量在当前shell中进行评估,这意味着它们在任何子进程开始之前就已经转换为当前PID。 子进程看到已经生成的PID。 换句话说,子进程执行的是echo 9098而不是echo $$
如果您想要子进程的PID,则必须防止父进程中的翻译,例如使用单引号:
bash -c 'echo $$'

1
如果您查阅"man bash",您可以在paxdiablo的回答中找到有关命令替换和特殊参数的信息。 - minopret
我想补充两件事: 1. 代码中有 5 个回显,其中有两个被捕获为字符串 (一个立即 echo ,另一个存储在变量中)。2. 在 bash 4.0 及更高版本中,环境变量 "$BASHPID" 将打印子 shell 的 PID。Bash 4.0 还不普及,请尝试运行 bash --version 查看你的版本。 - Mike

0
echo "one.sh $$"
echo `eval echo '$$'`

我期望上述代码会打印出不同的进程ID,但实际上并没有。它只是创建了一个子进程。通过在``中添加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中。据我所知,这是有意为之的,以使扩展保持不变,例如用于命名临时文件。 - torek
这是因为这个原因。 - tuxuday

-1
解决方案是$!。例如:
#!/bin/bash

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

输出:

$ ./prueba.sh
parent 30207
child 30209

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接