Shell脚本 全局变量、局部变量
在不同的作用域中,同名的变量不会相互干涉,就好像 A 班有个叫小明的同学,B 班也有个叫小明的同学,虽然他们都叫小明(对应于变量名),但是由于所在的班级(对应于作用域)不同,所以不会造成混乱。但是如果同一个班级中有两个叫小明的同学,就必须用类似于“大小明”、“小小明”这样的命名来区分他们。
Shell 变量的作用域可以分为三种:
- 有的变量只能在函数内部使用,这叫做局部变量(local variable);
- 有的变量可以在当前 Shell 进程中使用,这叫做全局变量(global variable);
- 而有的变量还可以在子进程中使用,这叫做环境变量(environment variable)。
Shell 局部变量
Shell 也支持自定义函数,但是 Shell 函数和 C++、Java、C# 等其他编程语言函数的一个不同点就是:在 Shell 函数中定义的变量默认也是全局变量,它和在函数外部定义变量拥有一样的效果。请看下面的代码:
- #!/bin/bash
- #定义函数
- function func(){
- a=99
- }
- #调用函数
- func
- #输出函数内部的变量
- echo $a
输出结果:
99
a 是在函数内部定义的,但是在函数外部也可以得到它的值,证明它的作用域是全局的,而不是仅限于函数内部。
要想变量的作用域仅限于函数内部,可以在定义时加上local命令,此时该变量就成了局部变量。请看下面的代码:
- #!/bin/bash
- #定义函数
- function func(){
- local a=99
- }
- #调用函数
- func
- #输出函数内部的变量
- 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 的代码如下:
- #!/bin/bash
- echo $a
- b=200
b.sh 的代码如下:
- #!/bin/bash
- 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脚本 全局变量、局部变量的更多相关文章
- shell脚本中局部变量local
shell脚本中局部变量 在shell中定义函数可以使代码模块化,便于复用代码.不过脚本本身的变量和函数的变量的作用域问题可能令你费解,在这里梳理一下这个问题. (1)Shell脚本中定义的变量是gl ...
- shell脚本一
在一些复杂的Linux维护工作中,大量重复的输入和交互操作不但费时费力,容易出错.这时候就需要用到脚本. 编写脚本的好处: 批量的处理,自动化的完成维护,减轻管理员的负担. linux的shell脚 ...
- Linux&shell之高级Shell脚本编程-创建函数
写在前面:案例.常用.归类.解释说明.(By Jim) 使用函数 #!/bin/bash # testing the script function myfun { echo "This i ...
- Linux Shell脚本编程的注意事项
Linux下(Shell脚本 http://www.jbxue.com/jb/shell/)编程的一些注意事项,如编程风格.命名风格等. 一.常用技巧 ssh user@server bash < ...
- Shell脚本编程总结及速查手册
Shell是一种编程语言, 它像其它编程语言如: C, Java, Python等一样也有变量/函数/运算符/if语句/循环控制/… 但在开始之前, 我想先理清Shell语言与Shell之间的关系. ...
- Shell脚本笔记
如何查询文件里的某个字符串? grep “字符串” 文件 例:grep "abc" tmp.txt 如何将查询出来的内容赋给变量? str=$(grep "abc ...
- 《Linux命令行与shell脚本编程大全》 第十六章 学习笔记
第十六章:创建函数 基本的脚本函数 创建函数 1.用function关键字,后面跟函数名 function name { commands } 2.函数名后面跟空圆括号,标明正在定义一个函数 name ...
- Shell 脚本常用命令
Shell脚本是Linux开发工作中常用的工具,但是我一直没有找到一个适合自己的简明扼要的HandBook.在工作过程中整理了一下,贴在这里已备查看. 1 Shell中的特殊符号 ...
- [转载]关于shell脚本的基本语法
关于shell脚本的基本语法 整理于:2014-03-31,何俭飞,mymladdr@sina.com 一.执行 1.shell脚本如果要被执行,一般地必须要有执行权限"x"(除了 ...
随机推荐
- (转)Unity Cinemachine插件,实现单目标和多目标之间切换
Unity Cinemachine插件学习笔记,实现单目标和多目标之间切换*版本要求Unity2017.1及以上. 参考资料: [官方] Unity 2017.1正式版发布 Cinemachine插件 ...
- systemd-tmpfiles - Operation not permitted chown ; systemd-modules-load.service
systemd-tmpfiles-setup.service fail 一般为 /exports/rfs/var/lib/systemd/ 下的文件属性问题 , chown -R root:r ...
- C# 进制转换(二进制、十六进制、十进制互转) 转载 https://www.cnblogs.com/icebutterfly/p/8884023.html
C# 进制转换(二进制.十六进制.十进制互转)由于二进制数在C#中无法直接表示,所以所有二进制数都用一个字符串来表示例如: 二进制: 1010 表示为 字符串:"1010" int ...
- vue 通过插槽分发内容
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- Thread.Join理解
Thread.Join:Blocks the calling thread until a thread terminates MainThread里面起了一个SubThread,从SubThread ...
- SpringDataRedis依赖
<dependencies> <dependency> <groupId>junit</groupId> ...
- 【基础】Linux软件安装方法
linux中wget .apt-get.yum rpm区别 wget 类似于迅雷,是一种下载工具, 通过HTTP.HTTPS.FTP三个最常见的TCP/IP协议下载,并可以使用HTTP代理 名字是Wo ...
- Java中连接MySql数据库的例子
Java中连接MySql数据库的例子: package com.joinmysql.demo; import java.sql.DriverManager; import java.sql.Resul ...
- java——IO(普通文件,二进制文件,压缩文件 )
二进制文件 压缩包
- lvs+keepalived+mariadb集群
1.环境准备节点1:172.16.2.95节点2:172.16.2.160节点3:172.16.2.220LVS1:172.16.2.67LVS2:172.16.2.234 2.mariadb集群的安 ...