linux 判断子进程,如何检测子Shell和子进程

上节我们说了子 Shell 和子进程的区别,这节就来看一下如何检测它们。

我们都知道使用 $ 变量可以获取当前进程的 ID,我在父 Shell 和子 Shell 中都输出 $ 的值,只要它们不一样,不就是创建了一个新的进程吗?那我们就来试一下吧。

[mozhiyan@localhost ~]$ echo $$ #父Shell PID

3299

[mozhiyan@localhost ~]$ (echo $$) #组命令形式的子Shell PID

3299

[mozhiyan@localhost ~]$ echo "http://c.biancheng.net" | { echo $$; } #管道形式的子Shell PID

3299

[mozhiyan@localhost ~]$ read <

[mozhiyan@localhost ~]$ echo $REPLY

3299

你看,子 Shell 和父 Shell 的 ID 都是一样的,哪有产生新进程了?作者你是不是骗人呢?

其实不是我骗人,而是你掉坑里了,因为 $ 变量在子 Shell 中无效!Base 官方文档说,在普通的子进程中,$ 确实被展开为子进程的 ID;但是在子 Shell 中,$ 却被展开成父进程的 ID。

除了 $,Bash 还提供了另外两个环境变量——SHLVL 和 BASH_SUBSHELL,用它们来检测子 Shell 非常方便。

SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,每次进入一层普通的子进程,SHLVL 的值就加 1。而 BASH_SUBSHELL 是记录一个 Bash 进程实例中多个子 Shell(sub shell)嵌套深度的累加器,每次进入一层子 Shell,BASH_SUBSHELL 的值就加 1。

1) 我们还是用实例来说话吧,先说 SHLVL。创建一个脚本文件,命名为 test.sh,内容如下:

#!/bin/bash

echo "$SHLVL $BASH_SUBSHELL"

然后打开 Shell 窗口,依次执行下面的命令:

[mozhiyan@localhost ~]$ echo "$SHLVL $BASH_SUBSHELL"

2 0

[mozhiyan@localhost ~]$ bash #执行bash命令开启一个新的Shell会话

[mozhiyan@localhost ~]$ echo "$SHLVL $BASH_SUBSHELL"

3 0

[mozhiyan@localhost ~]$ bash ./test.sh #通过bash命令运行脚本

4 0

[mozhiyan@localhost ~]$ echo "$SHLVL $BASH_SUBSHELL"

3 0

[mozhiyan@localhost ~]$ chmod +x ./test.sh #给脚本增加执行权限

[mozhiyan@localhost ~]$ ./test.sh

4 0

[mozhiyan@localhost ~]$ echo "$SHLVL $BASH_SUBSHELL"

3 0

[mozhiyan@localhost ~]$ exit #退出内层Shell

exit

[mozhiyan@localhost ~]$ echo "$SHLVL $BASH_SUBSHELL"

2 0

SHLVL 和 BASH_SUBSHELL 的初始值都是 0,但是输出结果中 SHLVL 的值从 2 开始,我猜测 Bash 在初始化阶段可能创建了子进程,我们暂时不用理会它,将关注点放在值的变化上。

仔细观察的读者应该会发现,使用 bash 命令开启新的会话后,需要使用 exit 命令退出才能回到上一级 Shell 会话。

bash ./test.sh和chmod +x ./test.sh; ./test.sh这两种运行脚本的方式,在脚本运行期间会开启一个子进程,运行结束后立即退出子进程。

2) 再说一下 BASH_SUBSHELL,请看下面的命令:

[mozhiyan@localhost ~]$ echo "$SHLVL $BASH_SUBSHELL"

2 0

[mozhiyan@localhost ~]$ (echo "$SHLVL $BASH_SUBSHELL") #组命令

2 1

[mozhiyan@localhost ~]$ echo "hello" | { echo "$SHLVL $BASH_SUBSHELL"; } #管道

2 1

[mozhiyan@localhost ~]$ var=$(echo "$SHLVL $BASH_SUBSHELL") #命令替换

[mozhiyan@localhost ~]$ echo $var

2 1

[mozhiyan@localhost ~]$ ( ( ( (echo "$SHLVL $BASH_SUBSHELL") ) ) ) #四层组命令

2 4

你看,组命令、管道、命令替换这几种写法都会进入子 Shell。

注意,“进程替换”看起来好像产生了一个子 Shell,其实只是玩了一个障眼法而已。进程替换只是借助文件在()内部和外部的命令之间传递数据,但是它并没有创建子 Shell;换句话说,()内部和外部的命令是在一个进程(也就是当前进程)中执行的。

我们不妨来实际检测一下:

[mozhiyan@localhost ~]$ echo "$SHLVL $BASH_SUBSHELL"

2 0

[mozhiyan@localhost ~]$ echo "hello" > >(echo "$SHLVL $BASH_SUBSHELL")

2 0

SHLVL 和 BASH_SUBSHELL 变量的值都没有发生改变,说明进程替换既没有进入子进程,也没有进入子 Shell。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值