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).

Bash Cookbook 说:

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 两个变量的区别的更多相关文章

  1. mysql 存储过程中的declare 和 set @的两种变量的区别

    两者在手册中的说明: DECLARE var_name[,...] type [DEFAULT value]这个语句被用来声明局部变量.要给变量提供一个默认值,请包含一个DEFAULT子句.值可以被指 ...

  2. 网站开发进阶(六)JSP两种声明变量的区别

    JSP两种声明变量的区别 在JSP中用两种声明变量的方法,一种是在<%! %>内,一种是在<% %>内.他们之间有什么区别呢?我们直接看一个JSP文件来理解. 代码如下: &l ...

  3. jsp中两种include的区别【转】

    引用文章:http://www.ibm.com/developerworks/cn/java/j-jsp04293/ http://www.cnblogs.com/lazycoding/archive ...

  4. locale的设定及其LANG、LC_ALL、LANGUAGE环境变量的区别

    locale这个单词中文翻译成地区或者地域,其实这个单词包含的意义要宽泛很多.Locale是根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境. [ora ...

  5. C#属性和变量的区别学习

    参考一   昨天看三层架构 (具体没怎么弄懂) 发现一般有一页代码专门用户存放字段的 而且都用用属性封装..令我诧异的是 很多字段属性都存在 get{}和set{} 和普通的变量没什么区别(可读可写) ...

  6. Ajax的get和post两种请求方式区别

    Ajax的get和post两种请求方式区别 (摘录):http://ip-10000.blog.sohu.com/114437748.html 解get和post的区别. 1. get是把参数数据队列 ...

  7. Linux set、env、declare、export显示shell变量的区别

    目录 Linux中 set.env.declare.export显示shell变量的区别 1. shell局部变量 2. 用户的环境变量 显示shell变量 declare 命令 export 命令 ...

  8. PHP 闭包获取外部变量和global关键字声明变量的区别

    最近在学习workerman的时候比较频繁的接触到回调函数,使用中经常会因为worker的使用方式不同,会用这两种不同的方式去调用外部的worker变量,这里就整理一下PHP闭包获取外部变量和glob ...

  9. java 类方法和实例方法 以及 类变量和实例变量 各种区别

    我们已经知道类体中的方法分为实例方法和类方法两种,用static修饰的是类方法.二者有什么区别呢?当一个类创建了一个对象后,这个对象就可以调用该类的方法. 当类的字节码文件被加载到内存时,类的实例方法 ...

随机推荐

  1. [django]从前端返回字符串,后端转换为字典,执行数据添加操作

    具体如题: js代码如下: $('#bill_add').click(function(){//合同添加 var bill1 = $("#bill1").val();var bil ...

  2. 《Inside UE4》目录

    <Inside UE4>目录 InsideUE4 UE4无疑是非常优秀的世界上最顶尖的引擎之一,性能和效果都非常出众,编辑器工作流也非常的出色,更难得宝贵的是完全的开源让我们有机会去从中吸 ...

  3. Linux Core Dump

    当程序运行的过程中异常终止或崩溃,操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为就叫做Core Dump(中文有的翻译成“核心转储”).我们可以认为 core dump 是“内存快 ...

  4. WinCE非通用调试工具汇总

    WinCE-IIC调试助手(S3C2410) http://www.cnblogs.com/we-hjb/archive/2008/10/19/1314562.html WinCE下音频频谱显示(TD ...

  5. 你不知道的Javascript(上卷)读书笔记之二 ---- 词法作用域

    在前一篇文章中,我们把作用域定义为"管理.维护变量的一套规则",接下来是时候来深入讨论一下Js的作用域问题了,首先我们要知道作用域一般有两种主要的工作类型,一种是词法作用域,一种是 ...

  6. CF724B. Batch Sort[枚举]

    B. Batch Sort time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  7. jQuery超链接提示,提示跟随鼠标动

    功能:实现鼠标移动到一个超链接时,鼠标右下角产生一个提示,并跟谁鼠标移动,知道鼠标离开超链接. 效果: 源码: <!--本案例是鼠标放在超链接上时,鼠标旁边有提示这是个超练级,以及放在图片上时图 ...

  8. 在MySQL中出现Unknown column 'abc' in 'field list'怎么解决?

    update TABLE1 set NAME = '?' where  ID  ='?' 参数字段需要添引号.

  9. 常用Git代码托管服务分享

    Git Repository代码托管服务越来越流行,目前有很多商业公司和个人团队逐渐切换项目到 Git平台进行代码托管.本文分享一些常用的Git代码托管服务,其中一些提供私有项目保护服务,特别有利于远 ...

  10. 部署 OpenStack VirtualBox

    VirtualBox 中部署 OpenStack 大家新年好,CloudMan 今天给大家带来一件新年礼物. 一直以来大家都反馈 OpenStack 学习有两大障碍:1. 实验环境难搭2. 体系复杂, ...