如何检测子Shell和子进程
发布时间:2020-12-14 02:15:23 所属栏目:Linux 来源:网络整理
导读:上节我们说了子 Shell 和子进程的区别,这节就来看一下如何检测它们。 我们都知道使用 $ 变量可以获取当前进程的 ID,我在父 Shell 和子 Shell 中都输出 $ 的值,只要它们不一样,不就是创建了一个新的进程吗?那我们就来试一下吧。 [mozhiyan@localhost ~]$
上节我们说了子 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 < <(echo $$) #进程替换形式的子Shell PID [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 0SHLVL 和 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 0SHLVL 和 BASH_SUBSHELL 变量的值都没有发生改变,说明进程替换既没有进入子进程,也没有进入子 Shell。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- linux – 绑定到虚拟接口的路由,Debian,以及如何在事后确定
- linux – 如何使用Ansible从远程机器获取多个文件到本地
- CentOS安装SVN服务器
- letecode [405] - Convert a Number to Hexadecimal
- linux – apt-get install期间debconf或perl错误
- linux – 在与我的站点不同的服务器上设置FTP
- linux – 如何配置bash来处理CRLF shell脚本?
- Linux基础:dirname命令总结
- LINUX学习:CentOS 6.9下Go1.8安装配置
- linux – 在Ubuntu 14.04 LTS上安装Navicat