SHLVL 和 BASH_SUBSHELL 两个变量的区别
SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,而 BASH_SUBSHELL 是记录一个 Bash 进程实例中多个子 Shell(subshell)嵌套深度的累加器。
看不懂上面这句话不要紧,因为是我临时编的。其实如果你混淆了这两个变量,我猜你多半是对 BASH_SUBSHELL 这个变量名中的 subshell 概念不清,下面我们就讲讲什么是 subshell,什么不是。
很多人误以为在 Bash 里面再执行一次 Bash,或者再执行一个 Shell 脚本就是进入子 Shell 了,所以他们会有下面这样的疑问:
|
$ bash # 执行另外一个 bash 命令 $ echo $BASH_SUBSHELL $ 0 # 怎么还是 0,我这不是在上个 Shell 的子 Shell 里吗? $ echo ' echo $BASH_SUBSHELL ' > test; chmod +x test; ./test; $ 0 # 难道再执行 Shell 脚本也不是子 Shell? |
然而并不是,这些都不是子 Shell,这种情况只能描述成是“当前 Shell 启动了个外部命令,而这个外部命令刚好是个 Shell”,真正的子 Shell 是不需要重新执行硬盘上的外部命令的,全部是内存中的操作。上面这个示例中的 BASH_SUBSHELL 都应该替换成 SHLVL 才能看到累加效果。
有几本书给子 Shell 下过定义:
Advanced Bash-Scripting Guide 说:
A subshell is a child process launched by a shell (or shell script).
A subshell is a forked copy of the parent shell and shares it’s environment.
The Korn Shell: Unix & Linux Programming Manual 说:
A subshell is a separate copy of the parent shell, so variables, functions, and aliases from the parent shell are available to the subshell
第一本书流传较广,但它这句话说的太泛了,很容易误导人,虽然子 Shell 的确是当前 Shell 的子进程,但当前 Shell 的子进程不一定都是子 Shell(可能已经替换成了其他程序)。在 Bash 里面,只有特定的语法才会让代码进入子 Shell,比如管道两边的命令,比如用小括号括起来等等:
|
$ (echo $BASH_SUBSHELL) 1 $ ( ( ( ( (echo $BASH_SUBSHELL) ) ) ) ) 5 |
真正的子 Shell 可以访问其父 Shell 的任何变量,而通过再执行一次 bash 命令所启动的 Shell 只能访问其父 Shell 传来的环境变量。这篇教程里面专门写了个例子:
For an example of the difference between a subshell and a child process that happens to be a shell:
unset a; a=1
(echo "a is $a in the subshell")
sh -c 'echo "a is $a in the child shell"'In the subshell, the regular shell variable a is visible; but because it is not exported, the full child process does not see it.
上面的例子中把当前 Shell 执行外部命令 sh 启动的 Shell 叫做 child shell,可惜在中文里还是得翻译成子 Shell。。。
从 c 语言层面讲,真正的子 Shell 是当前 Shell 进程调用了 fork() 函数,在内存中复制出一个几乎一模一样的子进程。而执行 bash 命令启动的所谓 child shell 是在执行 fork() 函数的基础上,又执行了一次 execve() 函数,execve() 函数会重新加载硬盘上的 bash 命令并执行,替换刚才 fork 出来的那个 shell 进程,除了传入的环境变量外,是个崭新的进程。
总结一下就是说,SHLVL 变量是记录了所谓的 child shell 的嵌套深度,而 BASH_SUBSHELL 是记录了 subshell 的嵌套深度。
把 child shell 叫成子 Shell,在口头上说说还可以,因为中文里没有其它什么好的叫法用来指代它,但你心里得明白,这不是术语子 Shell 真正的含义。
写到这里,我想这篇文章的标题应该改成“什么是子 Shell”了。
SHLVL 和 BASH_SUBSHELL 两个变量的区别的更多相关文章
- mysql 存储过程中的declare 和 set @的两种变量的区别
两者在手册中的说明: DECLARE var_name[,...] type [DEFAULT value]这个语句被用来声明局部变量.要给变量提供一个默认值,请包含一个DEFAULT子句.值可以被指 ...
- 网站开发进阶(六)JSP两种声明变量的区别
JSP两种声明变量的区别 在JSP中用两种声明变量的方法,一种是在<%! %>内,一种是在<% %>内.他们之间有什么区别呢?我们直接看一个JSP文件来理解. 代码如下: &l ...
- jsp中两种include的区别【转】
引用文章:http://www.ibm.com/developerworks/cn/java/j-jsp04293/ http://www.cnblogs.com/lazycoding/archive ...
- locale的设定及其LANG、LC_ALL、LANGUAGE环境变量的区别
locale这个单词中文翻译成地区或者地域,其实这个单词包含的意义要宽泛很多.Locale是根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境. [ora ...
- C#属性和变量的区别学习
参考一 昨天看三层架构 (具体没怎么弄懂) 发现一般有一页代码专门用户存放字段的 而且都用用属性封装..令我诧异的是 很多字段属性都存在 get{}和set{} 和普通的变量没什么区别(可读可写) ...
- Ajax的get和post两种请求方式区别
Ajax的get和post两种请求方式区别 (摘录):http://ip-10000.blog.sohu.com/114437748.html 解get和post的区别. 1. get是把参数数据队列 ...
- Linux set、env、declare、export显示shell变量的区别
目录 Linux中 set.env.declare.export显示shell变量的区别 1. shell局部变量 2. 用户的环境变量 显示shell变量 declare 命令 export 命令 ...
- PHP 闭包获取外部变量和global关键字声明变量的区别
最近在学习workerman的时候比较频繁的接触到回调函数,使用中经常会因为worker的使用方式不同,会用这两种不同的方式去调用外部的worker变量,这里就整理一下PHP闭包获取外部变量和glob ...
- java 类方法和实例方法 以及 类变量和实例变量 各种区别
我们已经知道类体中的方法分为实例方法和类方法两种,用static修饰的是类方法.二者有什么区别呢?当一个类创建了一个对象后,这个对象就可以调用该类的方法. 当类的字节码文件被加载到内存时,类的实例方法 ...
随机推荐
- hdu5317 RGCDQ (质因子种数+预处理)
RGCDQ 题意:F(x)表示x的质因子的种数.给区间[L,R],求max(GCD(F(i),F(j)) (L≤i<j≤R).(2<=L < R<=1000000) 题解:可以 ...
- JS入门学习,写一个简单的图片库
<!-- 新手刚开始学JS,每天坚持写点东西 坚持下去,希望能有所进步 . 加油~~ --> <!DOCTYPE html> ...
- 第8章 文件系统管理(2)_挂载、fdisk分区及分配swap分区
3. fdisk分区 3.1 fdisk命令分区过程 (1)添加新硬盘 (2)查看新硬盘#fdisk –l (3)使用fdisk命令分区:#fdisk /dev/sdb Fdisk交互指令说明 命令 ...
- IntelliJ IDEA设置JVM运行参数
2015十一月 28 原 IntelliJ IDEA设置JVM运行参数 分类:JavaSE (11566) (1) 打开 IDEA 安装目录,看到有一个 bin 目录,其中有两个 vmoptions ...
- 鼠标/手指相对于元素的坐标(px转百分比)
鼠标/手指相对于元素的坐标:鼠标或手指当前的位置 - 元素距离文档的位置 px转百分比:px / 文档尺寸 * 100 获取手指触摸在屏幕中相对于元素的坐标(px转百分比): $('#div').on ...
- 第二天----列表、元组、字符串、算数运算、字典、while
列表 列表是最常用的Python数据类型,它可以作为一个方括号内的逗号分隔值出现. 基本操作: 索引切片追加删除长度切片循环包含 创建.查看列表: 列表中的数字不要加引号,列表的索引从0开始: lis ...
- codevs 2894 保留小数
时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 给你一个实数,小数点后不超过50位,请你保留到小数点后n位(四舍五入!!!) 输 ...
- codevs 1015 计算器的改良 2000年NOIP全国联赛普及组
时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description NCL是一家专门从事计算器改良与升级的实验室,最近该实验室收到了某公司所委 ...
- gradle项目中profile的实现
gradle中并没有直接类似maven中的profile支持,只能变通的用其它方法来处理,在打包不同环境的应用时,通常会遇到二类问题: 一.不同的环境依赖的jar包不同 拿web开发来说,生产环境一般 ...
- tensorflow学习笔记三:实例数据下载与读取
一.mnist数据 深度学习的入门实例,一般就是mnist手写数字分类识别,因此我们应该先下载这个数据集. tensorflow提供一个input_data.py文件,专门用于下载mnist数据,我们 ...