在不同的作用域中,同名的变量不会相互干涉,就好像 A 班有个叫小明的同学,B 班也有个叫小明的同学,虽然他们都叫小明(对应于变量名),但是由于所在的班级(对应于作用域)不同,所以不会造成混乱。但是如果同一个班级中有两个叫小明的同学,就必须用类似于“大小明”、“小小明”这样的命名来区分他们。

Shell 变量的作用域可以分为三种:

  • 有的变量只能在函数内部使用,这叫做局部变量(local variable);
  • 有的变量可以在当前 Shell 进程中使用,这叫做全局变量(global variable);
  • 而有的变量还可以在子进程中使用,这叫做环境变量(environment variable)。

Shell 局部变量

Shell 也支持自定义函数,但是 Shell 函数和 C++JavaC# 等其他编程语言函数的一个不同点就是:在 Shell 函数中定义的变量默认也是全局变量,它和在函数外部定义变量拥有一样的效果。请看下面的代码:

  1. #!/bin/bash
  2. #定义函数
  3. function func(){
  4. a=99
  5. }
  6. #调用函数
  7. func
  8. #输出函数内部的变量
  9. echo $a

输出结果:
99

a 是在函数内部定义的,但是在函数外部也可以得到它的值,证明它的作用域是全局的,而不是仅限于函数内部。

要想变量的作用域仅限于函数内部,可以在定义时加上local命令,此时该变量就成了局部变量。请看下面的代码:

  1. #!/bin/bash
  2. #定义函数
  3. function func(){
  4. local a=99
  5. }
  6. #调用函数
  7. func
  8. #输出函数内部的变量
  9. echo $a

输出结果为空,表明变量 a 在函数外部无效,是一个局部变量。

Shell 变量的这个特性和 JavaScript 中的变量是类似的。在 JavaScript 函数内部定义的变量,默认也是全局变量,只有加上var关键字,它才会变成局部变量。

本节只是演示了函数的定义和调用,并没有对语法细节作过多说明,后续我们将在《Shell函数》一节中进行深入讲解。

Shell 全局变量

所谓全局变量,就是指变量在当前的整个 Shell 进程中都有效。每个 Shell 进程都有自己的作用域,彼此之间互不影响。在 Shell 中定义的变量,默认就是全局变量。

想要实际演示全局变量在不同 Shell 进程中的互不相关性,可在图形界面下同时打开两个 Shell,或使用两个终端远程连接到服务器(SSH)。

首先打开一个 Shell 窗口,定义一个变量 a 并赋值为 99,然后打印,这时在同一个 Shell 窗口中是可正确打印变量 a 的值的。然后再打开一个新的 Shell 窗口,同样打印变量 a 的值,但结果却为空,如图 1 所示。


图1:打开两个 Shell 窗口

这说明全局变量 a 仅仅在定义它的第一个 Shell 进程中有效,对新的 Shell 进程没有影响。这很好理解,就像小王家和小徐家都有一部电视机(变量名相同),但是同一时刻小王家和小徐家的电视中播放的节目可以是不同的(变量值不同)。

需要强调的是,全局变量的作用范围是当前的 Shell 进程,而不是当前的 Shell 脚本文件,它们是不同的概念。打开一个 Shell 窗口就创建了一个 Shell 进程,打开多个 Shell 窗口就创建了多个 Shell 进程,每个 Shell 进程都是独立的,拥有不同的进程 ID。在一个 Shell 进程中可以使用 source 命令执行多个 Shell 脚本文件,此时全局变量在这些脚本文件中都有效。

例如,现在有两个 Shell 脚本文件,分别是 a.sh 和 b.sh。a.sh 的代码如下:

  1. #!/bin/bash
  2. echo $a
  3. b=200

b.sh 的代码如下:

  1. #!/bin/bash
  2. echo $b

打开一个 Shell 窗口,输入以下命令:

[c.biancheng.net]$ a=99
[c.biancheng.net]$ . ./a.sh
99
[c.biancheng.net]$ . ./b.sh
200

这三条命令都是在一个进程中执行的,从输出结果可以发现,在 Shell 窗口中以命令行的形式定义的变量 a,在 a.sh 中有效;在 a.sh 中定义的变量 b,在 b.sh 中也有效,变量 b 的作用范围已经超越了 a.sh。

注意,必须在当前进程中运行 Shell 脚本,不能在新进程中运行 Shell 脚本,不了解的读者请转到《执行Shell脚本》。

Shell 环境变量

全局变量只在当前 Shell 进程中有效,对其它 Shell 进程和子进程都无效。如果使用export命令将全局变量导出,那么它就在所有的子进程中也有效了,这称为“环境变量”。

环境变量被创建时所处的 Shell 进程称为父进程,如果在父进程中再创建一个新的进程来执行 Shell 命令,那么这个新的进程被称作 Shell 子进程。当 Shell 子进程产生时,它会继承父进程的环境变量为自己所用,所以说环境变量可从父进程传给子进程。不难理解,环境变量还可以传递给孙进程。

注意,两个没有父子关系的 Shell 进程是不能传递环境变量的,并且环境变量只能向下传递而不能向上传递,即“传子不传父”。

创建 Shell 子进程最简单的方式是运行 bash 命令,如图 2 所示。


图2:进入 Shell 子进程

通过exit命令可以一层一层地退出 Shell。

下面演示一下环境变量的使用:

[c.biancheng.net]$ a=22       #定义一个全局变量
[c.biancheng.net]$ echo $a #在当前Shell中输出a,成功
22
[c.biancheng.net]$ bash #进入Shell子进程
[c.biancheng.net]$ echo $a #在子进程中输出a,失败 [c.biancheng.net]$ exit #退出Shell子进程,返回上一级Shell
exit
[c.biancheng.net]$ export a #将a导出为环境变量
[c.biancheng.net]$ bash #重新进入Shell子进程
[c.biancheng.net]$ echo $a #在子进程中再次输出a,成功
22
[c.biancheng.net]$ exit #退出Shell子进程
exit
[c.biancheng.net]$ exit #退出父进程,结束整个Shell会话

可以发现,默认情况下,a 在 Shell 子进程中是无效的;使用 export 将 a 导出为环境变量后,在子进程中就可以使用了。

export a这种形式是在定义变量 a 以后再将它导出为环境变量,如果想在定义的同时导出为环境变量,可以写作export a=22

我们一直强调的是环境变量在 Shell 子进程中有效,并没有说它在所有的 Shell 进程中都有效;如果你通过终端创建了一个新的 Shell 窗口,那它就不是当前 Shell 的子进程,环境变量对这个新的 Shell 进程仍然是无效的。请看下图:

第一个窗口中的环境变量 a 在第二个窗口中就无效。

环境变量也是临时的

通过 export 导出的环境变量只对当前 Shell 进程以及所有的子进程有效,如果最顶层的父进程被关闭了,那么环境变量也就随之消失了,其它的进程也就无法使用了,所以说环境变量也是临时的。

Shell脚本 全局变量、局部变量的更多相关文章

  1. shell脚本中局部变量local

    shell脚本中局部变量 在shell中定义函数可以使代码模块化,便于复用代码.不过脚本本身的变量和函数的变量的作用域问题可能令你费解,在这里梳理一下这个问题. (1)Shell脚本中定义的变量是gl ...

  2. shell脚本一

    在一些复杂的Linux维护工作中,大量重复的输入和交互操作不但费时费力,容易出错.这时候就需要用到脚本. 编写脚本的好处:  批量的处理,自动化的完成维护,减轻管理员的负担. linux的shell脚 ...

  3. Linux&shell之高级Shell脚本编程-创建函数

    写在前面:案例.常用.归类.解释说明.(By Jim) 使用函数 #!/bin/bash # testing the script function myfun { echo "This i ...

  4. Linux Shell脚本编程的注意事项

    Linux下(Shell脚本 http://www.jbxue.com/jb/shell/)编程的一些注意事项,如编程风格.命名风格等. 一.常用技巧 ssh user@server bash < ...

  5. Shell脚本编程总结及速查手册

    Shell是一种编程语言, 它像其它编程语言如: C, Java, Python等一样也有变量/函数/运算符/if语句/循环控制/… 但在开始之前, 我想先理清Shell语言与Shell之间的关系. ...

  6. Shell脚本笔记

      如何查询文件里的某个字符串? grep “字符串” 文件 例:grep "abc" tmp.txt   如何将查询出来的内容赋给变量? str=$(grep "abc ...

  7. 《Linux命令行与shell脚本编程大全》 第十六章 学习笔记

    第十六章:创建函数 基本的脚本函数 创建函数 1.用function关键字,后面跟函数名 function name { commands } 2.函数名后面跟空圆括号,标明正在定义一个函数 name ...

  8. Shell 脚本常用命令

    Shell脚本是Linux开发工作中常用的工具,但是我一直没有找到一个适合自己的简明扼要的HandBook.在工作过程中整理了一下,贴在这里已备查看. 1           Shell中的特殊符号 ...

  9. [转载]关于shell脚本的基本语法

    关于shell脚本的基本语法 整理于:2014-03-31,何俭飞,mymladdr@sina.com 一.执行 1.shell脚本如果要被执行,一般地必须要有执行权限"x"(除了 ...

随机推荐

  1. git拉取远程所有分支

    第一步: git branch -r | grep -v '->' | while read remote; do git branch --track "${remote#origi ...

  2. ASE: CODEnn Reproduce

    Background 第二次结对编程的任务是挑选一个用自然语言搜索相关代码片段的模型实现,并且可以提出自己的想法改进.这个任务很cool,前期做了不少调研.使用自然语言搜索相关代码片段现在是个很受关注 ...

  3. 三重循环之break

    while(1) { while(1) { while(1) { break; } } } //逻辑堪比绝技啊 脑洞开之注册表循环遍历方法

  4. 【LeetCode】Hash

    [451] Sort Characters By Frequency [Medium] 给一个字符串,要求返回按照字母出现频率的排序后的字符串.(哈希表+桶排) 有个技巧是Hash用Value作为In ...

  5. java多线程面试题选择题大全含答案

    v java多线程面试题选择题大全含答案 java多线程面试题选择题大全含答案 1.下面程序的运行结果()(选择一项)public static void main(String[] args) {T ...

  6. vue 初始化rem

    在assets => js => rem.js export default { init () { let sw = document.documentElement.clientWid ...

  7. mybatis中配置文件头

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "- ...

  8. Robot Framework:日志输出中文Unicode编码

    robotframework 输出日志时,中文显示为Unicode编码 . 修改方法: 在Python27\Lib\site-packages\robotframework-3.0.4-py2.7.e ...

  9. Linux服务器的16个监控命令

    想不想知道你的服务器到底在干什么?那么你要知道本文介绍的这些基本命令.一旦你熟悉掌握了这些命令,就为成为专业的 Linux系统管理员打下了基础. 你可以通过图形化用户界面(GUI)程序来获取这些外壳命 ...

  10. NX二次开发-基于NX开发向导模板的NX对Excel读写操作(OLE方式(COM组件))

    在看这个博客前,请读者先去完整看完:NX二次开发-基于MFC界面的NX对Excel读写操作(OLE方式(COM组件))https://ufun-nxopen.blog.csdn.net/article ...