linux shell 子shell,关于"子"shell与子shell

在第二周课程中,老师说到使用小括号(list)可以调出子shell,并举了以下例子:

adb7603ec43e

这个例子很好理解:在当前shell,变量name被赋值为wang;而在通过()进入的子shell里,变量name被赋值为zhang。所以第一个echo显示当前shell内变量name的值为wang;第二个echo显示子shell内变量name的值为zhang;第三个echo是子shell结束后,回到当前shell,变量name的值为wang.

紧接着,老师又写了一行命令,让大家判断它的输出值会是什么:

adb7603ec43e

根据之前的经验,name作为当前shell的一个普通变量,并没有被export,子shell是不会继承的,输出值自然是“wang 空值 wang”咯。然后结果却出乎意料:

adb7603ec43e

怎么回事,在没有export的情况下,子shell怎么继承了父shell的环境变量?

课后特意去询问老师,老师大致解释说,用()打开的子shell与执行bash打开的子shell还是不同的,它没有单独加载一些shell的配置,会继承父shell的内容等等。本着先记住,以后慢慢理解的原则,我也就似懂非懂地决定先硬记住了。

但是两种子shell到底有什么区别呢?为什么一个能继承父shell的环境,另一个却不能呢?

今天无意中看到一篇帖子,里面解释了SHLVL和BASH_SUBSHELL两个变量,让这个疑惑迎刃而解。

首先,借用一下大神对这两个变量的定义:

SHLVL是记录多个bash进程实例嵌套深度的累加器

BASH_SUBSHELL是记录一个bash进程实例的多层subshell嵌套深度的累加器

如果概念比较不好理解,让我们通过例子来理解吧

adb7603ec43e

1

adb7603ec43e

2

图1中,SHLVL值随着bash命令执行的次数增加,而BASH_SUBSHELL值不变。本质上说,这是通过执行外部命令bash开启了新进程(而这个新进程恰好也是shell进程罢了),而SHLVL记录了这种嵌套的shell进程实例的层数。这样的child shell进程是通过执行硬盘上的命令来生成的,它是独立的(会读取加载/etc/profile.d/*.sh /etc/bashrc ~/.bashrc等bash配置文件),只能访问所谓的"父"shell的环境变量。

而通过()开启的叫做subshell的才是当前shell名副其实的子shell,它可以访问父shell的任何变量。图2可以看到通过()开启的子shell的嵌套层级数。注意,SHLVL的值是不变的,也就是没有开启新的child shell。

我们来看看进程树:

bash

adb7603ec43e

SHLVL

adb7603ec43e

SHLVL pstree

() 因为执行完小括号内的命令后,subshell进程会立马结束,所以需要通过sleep命令来留住subshell进程,进而通过pstree -p命令观察它

adb7603ec43e

()

adb7603ec43e

() pstree

从进程树上看,child shell和subshell他们都在当前shell进程(pid15036)后.不同点在于,child shell的$BASHPID和$$值相同,subshell则没有自己独立$$值,只有自己的$BASHPID.

翻译成中文的时候笼统地管它们叫子shell。然而它们是有本质上的区别的。现在你了解了吗?

补充:

An example of the difference between a subshell and a child process that happens to be a shell:

adb7603ec43e

补充2:

通过管道,也能打开subshell

adb7603ec43e

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值