目录
本文内容同微信公众号【凡登】,关注不迷路,学习上高速,欢迎关注共同学习。
什么是变量的作用范围? 变量在Shell脚本中的有效范围或可使用的范围, 什么是有效范围或可使用范围? 通过看一个示例看看
# 定义一个变量
[root@ ~]# name=joey
# 编辑脚本hi.sh 内容为:echo "$name, hello",定义以脚本方式查看变量
[root@ ~]# vim hi.sh
echo "$name, hello"
# 当前终端查看
[root@ ~]# echo "$name, hello"
joey, hello
# 当前bash进程查看,能查看到变量
[root@ ~]# source ./hi.sh
joey, hello
# bash子进程查看,不能查看到变量
[root@ ~]# bash hi.sh
, hello
# 新启终端查看,不能查看到变量
[root@ ~]# echo "$name, hello"
, hello
# 回到最初终端,导出变量后可以查看到,
[root@ ~]# export name ; bash hi.sh
joey, hello
从上面可以看到,当前进程和终端可以访问当前定义的变量,而子进程和新启终端访问不到变量,
当回到原终端通过export导出变量后,这时子进程可以访问到变量,然而新终仍然无法访问到变量,这是什么原因? 它就是本小节将要介绍的主题:变量的作用范围
这里从简单到复杂,依次递进的方式将变量作用范围分为以下6种场景:函数内的变量、shell脚本内的变量、进程内的变量、进程间的变量、终端间的变量、用户间的变量。
1、函数内的变量
函数内的变量也就是局部变量。看下示例
[root@ ~]# vi fun.sh
#!/bin/bash
function my_fun() {
echo "--------函数开始--------------"
local local_var1="我是函数局部变量" # 定义局部变量 var
echo "执行函数:$local_var1 !" # 输出局部变量的值
echo "--------函数结束--------------"
}
echo "执行函数前:$local_var1 !"
my_fun # 执行函数
echo "执行函数后:$local_var1 !"
[root@ ~]# bash fun.sh
执行函数前: !
--------函数开始--------------
执行函数:我是函数局部变量 !
--------函数结束--------------
执行函数后: !
小结:局部变量在函数中有效,超过函数范围就失效。
那可以在shell脚本中定义局部变量? 不可以。局部变量只能在函数中定义,
如下图错误示例:
[root@ ~]# vim fun_local_err.sh
local v=123
[root@ ~]# bash fun_local_err.sh
fun_local_err.sh: line 1: local: can only be used in a function
[root@ ~]# local vv=123
bash: local: can only be used in a function
2、shell脚本内的变量
在shell脚本中定义的变量作用范围分为:局部变量和全局变量,局部变量在某个区域内有效,如函数块内。全局变量时整个shell脚本运行中有效,一旦脚本运行结束,全局变量就会失效。这里重点介绍全局变量
[root@ ~]# vi fun.sh
#!/bin/bash
global_var1="我是脚本全局变量"
function my_fun() {
echo "--------函数开始--------------"
global_var2="我是函数全局变量"
echo "执行函数:$global_var2 !"
echo "--------函数结束--------------"
}
echo "执行函数前:$global_var1 !"
echo "执行函数前:$global_var2 !"
my_fun # 执行函数
echo "执行函数后:$global_var1 !"
echo "执行函数后:$global_var2 !"
[root@ ~]# bash fun.sh
执行函数前:我是脚本全局变量 !
执行函数前: !
--------函数开始--------------
执行函数:我是函数全局变量 !
--------函数结束--------------
执行函数后:我是脚本全局变量 !
执行函数后:我是函数全局变量 !
全局变量作用域在shell脚本都有效,访问前必须先定义好变量。忽略是否在函数中定义,如例子所示,即使在函数中定义,当函数执行完后,全局变量仍有效。
总结:局部变量只能在函数中定义和使用,且作用域在函数内。全局变量作用范围在整个脚本中,需要注意定义变量位置需在访问之前,且不受函数作用域范围的影响。
3、进程内的变量
进程内变量描述的是bash进程中的变量。
在介绍进程内变量之前,先回顾下脚本执行不同方式所带来的影响,
bash xxx.sh 新起子进程执行xxx.sh , 脚本中行为只在子进程有效,对父进程环境没影响,
source ./xxx.sh 在当前进程执行xxx.sh ,脚本行为对当前进程环境有影响。
. xxx.sh 是source ./xxx.sh简写形式
./xxx.sh 新起子进程执行xxx.sh,
4种不同执行方式和区别详情参见《shell简单认知》脚本的执行方式。回到本节主题进程变量的作用范围
# 新建脚本hi.sh,内容为echo "$name, hello"
[root@ ~]# echo 'echo "$name, hello"' > hi.sh
# 当前进程新建变量name=123
[root@ ~]# name=123
[root@ ~]# echo $name
123
# bash xxx.sh执行脚本,以子进程方式访问访问父进程name
[root@ ~]# bash hi.sh
, hello
# source ./xxx.sh执行脚本,在当前进程访问name
[root@ ~]# source hi.sh
123, hello
# . xxx.sh 是 source ./xxx.sh的简写形式
[root@ ~]# . hi.sh
123, hello
# ./xx.sh子进程方式执行脚本
[root@ ~]# chmod u+x hi.sh
[root@ ~]# ./hi.sh
, hello
以上执行结果表明,同一进程变量访问不受限制,但子进程无法访问到父进程变量, 进程中的变量作用仅在当前进程的范围内有效,即进程变量也有自己的作用范围。
问:如何跨进程访问,让子进程也可以访问父进程变量,实现进程间的变量共享?
见第4节《进程间的变量》
4、进程间的变量
进程间变量描述的是父子进程间变量。被export关键字修饰的变量,可以在进程间传递,也可以被子进程继承,从而在进程间实现变量共享。在第3节《进程内变量》例子中 bash hi.sh 访问不到name, 那么用export修饰name,再看执行结果
# 导出当前变量
[root@ ~]# export name
# bash xxx.sh 方式访问父进程变量name
[root@ ~]# bash hi.sh
123, hello
# ./xxx.sh 方式访问父进程变量name
[root@ ~]# ./hi.sh
123, hello
执行结果看出,当用export修饰name变量后,就可以访问父进程name变量。
export命令设置的变量是环境变量。
环境变量是在操作系统中用于存储各种配置信息的一种机制,通过设置环境变量,可以影响系统的行为和程序的运行。使用export命令,可以将一个变量从当前shell传递到子shell或其他进程中。当一个变量被导出后,它将成为子shell的环境变量,可以被其他命令和程序访问和使用
5、终端间的变量
在上一节学习了通过export修饰的变量可以在进程间传递,从而实现进程共享变量,那么能否在多个终端共享变量?先通过一个示例看看,在上述第4节《进程间的变量》例子中,新启一个终端,访问变量
# 新启终端访问
[root@ ~]#bash hi.sh
, hello
发现新启终端无法访问到上述通过export导出的环境变量,那么如何实现终端间的变量共享?
[root@ ~]# vim ~/.bashrc
export name=456
# 使用source ~/.bashrc加载配置文件
[root@ ~]# source ~/.bashrc
# 访问可以看到原值123已经变为456
[root@ ~]# bash hi.sh
456, hello
# 新启终端访问,可以访问到最新值456
[root@ ~]#bash hi.sh
456, hello
说明:
1、修改~/.bashrc,如果不使用source ~/.bashrc加载,那么访问的仍然是原来的值;
当前终端立即访问,则需要通过source ~/.bashrc重新加载配置
新终端会重新加载配置,无需再使用source ~/.bashrc加载配置文件
2、写入~/.bashrc中的变量可以跨终端进行访问
在bashrc中修改的值无法被立即访问,是因为修改的变量只在当前Shell进程中生效,而不会影响到父进程或其他子进程。当在bashrc中添加或修改环境变量时,这些变量只会对当前Shell及其子进程起作用,而不会影响其他已经运行的Shell或系统级的环境变量
如果你希望在脚本中访问在bashrc中定义的变量,可以在脚本中通过source命令加载~/.bashrc文件。这样,脚本就会继承bashrc中定义的所有变量和配置。
通过上述bashrc配置文件实现终端共享变量。
6、用户间的变量
在上一节学习了通过export修饰的变量可以在进程间传递,从而实现进程共享变量;通过~/.bashrc配置变量实现跨终端共享变量,那么能否在不同用户间共享变量?先通过一个示例看看
# 创建新用户
[root@ ~]# useradd joy
[root@ ~]# passwd joy
# 创建脚本访问name和NAME变量
[root@ ~]# vi hi.sh
echo "$name, hello"
echo "$NAME, hello"
echo "$_name, hello"
# 将root脚本复制到用户joy家目录下
[root@ ~]# cp /root/hi.sh /home/joy/
# 定义name和NAME,_name变量
[root@ ~]# name=123
[root@ ~]# export NAME=456
[root@ ~]# vim ~/.bashrc
export _name=123456
# 加载bashrc配置文件
[root@ ~]# source ~/.bashrc
# root用户下访问变量
[root@ ~]# source ./hi.sh
123, hello
456, hello
123456, hello
# 切换joy用户, 使用-表示用户登录加载所有配置文件
[root@ ~]# su - joy
# joy用户下执行脚本访问变量
[joy@ ~]$ source ./hi.sh
, hello
, hello
, hello
上面演示,不管是shell全局变量或通过export修饰的环境变量,还是定义在~/.bashrc配置文件的变量,当切换到新用户后都访问不到。说明这些不具备跨用户共享,那么如何才能做到切换用户仍然可以访问变量?
让我们在/etc/bashrc配置文件中新增变量,再观察一下
# 新增变量
[root@ ~]# vim /etc/bashrc
export _NAME=123456789
# 加载配置文件
[root@ ~]# source /etc/bashrc
# 在hi.sh后追加对_NAME的访问
[root@ ~]# vim hi.sh
echo "$_NAME, hello"
# 移动到joy用户家目录下
[root@ ~]# cp /root/hi.sh /home/joy/
# root用户下访问
[root@ ~]# source ./hi.sh
123, hello
456, hello
123456, hello
123456789, hello
# 切换joy用户并登录
[root@ ~]# su - joy
# joy用户下访问变量,哎,这回可以访问_NAME变量,
[joy@ ~]$ source ./hi.sh
, hello
, hello
, hello
123456789, hello
注:编辑/etc/bashrc需要root权限
从上面结果可以看出当切换用户后,定义在/etc/bashrc下的变量仍可以访问,至此我们自定义的变量,实现了跨进程,跨终端,跨用户进行访问了。
总结
通过示例演示从函数->脚本->进程内->跨进程->跨终端->跨用户不同场景中变量表现,引出变量的作用范围,使用local修饰变量使变量的作用范围控制在函数内,在脚本中定义变量可以在函数中共享,通过使用export修饰变量使其能在进程间传递,实现进程间共享变量,扩大变量作用范围,另外修改配置文件~/.bashrc和/etc/bashrc能使变量在多个终端和用户间共享,进一步扩大变量的作用范围,在日常工作中我们根据不同场景来限定变量范围,防止误伤。
问:~/.bashrc 和 /etc/bashrc配置文件是什么?为什么可以实现变量共享?还有没有类似配置文件?
这些就是变量的配置文件,将在《变量配置文件》中讲解。
再次感谢您的阅读,欢迎关注微信公众号【凡登】共同学习。