[Shell]-2-Bash环境变量
引言
Bash Shell使用环境变量(Environment Variable)来存储Bash会话与工作环境等信息,这种特性将数据存储在内存中,以便脚本或程序能够方便的读取与调用它们。
文章目录
0×1.Bash Shell环境变量简介
在Linux的Bash Shell中,我们可以简单的将"环境变量"这种特性想象成编程语言中的"变量",当我们启动一个Bash Shell时,系统会根据不同文件中的信息去初始化这些"变量",并将它们保存在内存中,这些保存在内存中的变量值,可以被Bash Shell中执行的程序或脚本调用。
在Bash Shell中,"环境变量"被分为两类:局部环境变量、全局环境变量。
局部环境变量,是在Bash Shell启动后被用户或程序创建的"变量",这些"变量"只能被创建它们的Shell调用;而全局环境变量是在Bash Shell启动时创建,能够被所有Shell或子Shell调用。
简而言之,全局环境变量对于Shell会话和所有生成的子Shell都是可见的;局部变量则只对创建它们的Shell可见。
0×2.局部环境变量
局部环境变量作用范围仅限于创建它们的Shell本身,例如:
#在当前Bash中创建一个名为"website"的变量,值是"www.qingsword.com" root@qingsword.com:~# website="www.qingsword.com" #使用echo输出这个变量的值 root@qingsword.com:~# echo $website www.qingsword.com #上面创建的变量作用范围仅仅是它本身,如果我再创建一个子Bash Shell root@qingsword.com:~# bash #用ps确认子Shell创建是成功的 root@qingsword.com:~# ps --forest PID TTY TIME CMD 2042 pts/0 00:00:00 bash 3303 pts/0 00:00:00 \_ bash 3307 pts/0 00:00:00 \_ ps #在这个子Shell上访问父Shell的"Website"变量,结果为空,不存在 root@qingsword.com:~# echo $website #退出子Shell root@qingsword.com:~# exit exit root@qingsword.com:~# ps --forest PID TTY TIME CMD 2042 pts/0 00:00:00 bash 3318 pts/0 00:00:00 \_ ps #这个实验就验证了,局部环境变量作用范围仅限于创建它的Shell本身 root@qingsword.com:~# echo $website www.qingsword.com #可以使用unset来删除这个变量 root@qingsword.com:~# unset website root@qingsword.com:~# echo $website
0×3.全局环境变量
在Shell启动或用Shell登录时,会根据系统中指定的几个文件中的方法去创建全局环境变量,这些文件会在本文第四部分中介绍到,可以使用下面的方法查看这些预设定的环境变量值:
#使用env命令来查看当前Shell加载的全局变量 root@qingsword.com:~# env #也可以使用printenv来查看,效果同上 root@qingsword.com:~# printenv #要想查看单独的某一个环境变量,可以使用echo或printenv命令,两者稍有不同 #使用echo要在变量名称前面加上"$"符 root@qingsword.com:~# echo $HOME /root #使用printenv直接加变量名称 root@qingsword.com:~# printenv HOME /root
除了系统预设的环境变量外,可以使用"export"命令将当前Bash Shell中的指定局部变量转化成全局变量,如果在当前Bash中新建一个子Bash,在子Bash中能够访问使用"export"命令定义的全局变量,在子Bash中能够改变这个全局变量的值,但是改变的值仅限于子Bash,不能改变父Bash中的这个变量值,在子Bash中,就算使用"export"命令也不能改变父Bash中全局环境变量的值,例如:
#首先在Bash中定义一个变量"website" root@qingsword.com:~# website="www.qingsword.com" root@qingsword.com:~# echo $website www.qingsword.com #将这个变量设置成全局变量 root@qingsword.com:~# export website #创建子Shell root@qingsword.com:~# bash root@qingsword.com:~# ps --forest PID TTY TIME CMD 2042 pts/0 00:00:00 bash 3602 pts/0 00:00:00 \_ bash 3606 pts/0 00:00:00 \_ ps #子Shell继承了父Shell设定的全局变量 root@qingsword.com:~# echo $website www.qingsword.com #尝试着更改子Shell中的"website"值 root@qingsword.com:~# website="qingsword.com" root@qingsword.com:~# echo $website qingsword.com #并且使用"export"命令将其设置成全局变量 root@qingsword.com:~# export website root@qingsword.com:~# exit exit #退出子Shell后,再次查看"website"值,发现子Shell对"website"值的更改不会影响到父Shell root@qingsword.com:~# echo $website www.qingsword.com
上面的这种全局变量,使用范围仅限于创建它的Bash及其子Bash,如果父Bash关闭后,这个全局变量就被清除了,并不会长期保存,可以使用本文第五小节的方法存储环境变量,让变量持久化。
0×4.启动Bash的三种方式
这一小节主要介绍Bash的几种启动方式需要加载和执行的文件,在第五小节中,会介绍如何利用这些被执行的文件来创建我们自定义的环境变量。
Shell的启动有如下三种方式:
登录时作为默认登录Shell(例如,字符界面登录);
作为非登录Shell的交互式Shell(例如,登录图形界面后启动一个Bash Shell);
作为运行脚本的非交互Shell(例如,在Bash中调用一个sh脚本);
1、登录时作为默认登录Shell
在Shell作为登录方式启动时,首先会从"/etc/profile"文件中读取命令,"/etc/profile"文件是Bash Shell默认的的主启动文件;只要登录了Linux系统,Bash就会执行"/etc/profile"启动文件中的命令;不同的Linux发行版在这个文件里放了不同的命令,Ubuntu中,这个文件内容如下:
#我们现在不需要知道这个文件的语法的意思,只需要知道这个文件去执行了"/etc/bash.bashrc"这个文件的内容,并且循环遍历"/etc/profile.d/"目录,执行这个目录下的sh脚本 qing@qingsword.com:~$ cat /etc/profile if [ "${PS1-}" ]; then if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then # The file bash.bashrc already sets the default PS1. # PS1='\h:\w\$ ' if [ -f /etc/bash.bashrc ]; then . /etc/bash.bashrc #执行这个文件的内容 fi else if [ "`id -u`" -eq 0 ]; then PS1='# ' else PS1='$ ' fi fi fi if [ -d /etc/profile.d ]; then for i in /etc/profile.d/*.sh; do #循环遍历"/etc/profile.d"目录,执行.sh后缀的脚本 if [ -r $i ]; then . $i fi done unset i fi
除了访问"/etc/profile"文件外,Linux还会依次去查找下面三个文件,系统会按照下面的顺序,运行第一个被找到的文件,余下的则被忽略:
$HOME/.bash_profile
$HOME/.bash_login
$HOME/.profile
Ps.上面三个文件,都保存在用户家目录,在一些版本的Linux中,上面这三个文件可能不会存在,但我们可以手动去创建这些文件,系统会遵循这个规则去依次读取这些文件执行。
2、作为非登录Shell的交互式Shell
如果你的"Bash Shell"不是登录系统时启动的(比如是在登录系统后启动的Shell),那么你启动的Shell就是交互式shell,如果Bash是作为交互式Shell启动的,它就不会访问/etc/profile文件(/etc/profile仅在Linux登录时被加载一次),只会加载用户HOME目录中的.bashrc文件,我们可以在.bashrc文件的末尾添加环境变量或者命令别名,作为启动Shell的初始变量。
3、非交互式 Shell
系统执行脚本时执行的Shell叫做非交互式Shell,非交互式的Bash Shell提供了"BASH_ENV" 环境变量来初始化这个Bash,当启动一个非交互式Shell进程时,它会检查这个环境变量来查看要执行的启动文件,在ubuntu中这个变量值为空,当这个环境变量值为空时,启动脚本的Bash Shell仍然会继承Linux登录时读取的"/etc/profile"文件、/etc/profile.d/ * .sh和$HOME/.bashrc文件中设置的环境变量。
0×5.用户自定义变量持久化
在第四节中已经讲解了Shell的启动过程中会加载哪些文件中的内容,那么如果要想在Shell启动时就加载我们设定的变量,可以通过下面几种方法:
1、将环境变量放在"/etc/profile"文件内容的末尾,或在/etc/profile.d目录中创建一个.sh脚本,例如:
#将website="www.qingsword.com"写入文件末尾(注意如果要写入单引号需要使用转义符) root@qingsword.com:~# echo website=\"www.qingsword.com\" >> /etc/profile #查看 root@qingsword.com:~# tail -n 3 /etc/profile website="www.qingsword.com"
写入之后,每次重启系统,都会自动加载website变量,并将值"www.qingsword.com"赋予给这个变量,除了使用这种方法外,还能在/etc/profile.d中创建一个.sh脚本,例如:
#创建一个myev.sh脚本 root@qingsword.com:~# vim /etc/profile.d/myev.sh #写入如下内容 #!/bin/bash website="www.qingsword.com"
从第四小节的内容不难理解,系统会遍历这个目录中的内容,然后逐个执行其中的sh脚本,当执行到我们创建的脚本时,就会创建一个全局环境变量"website"。
Ps.当然,我们也能将这些环境变量的初始化语句放在用户家目录的".bash_profile"、".bash_login"、".profile"这三个文件的任意一个中。
2、作为交互式登录的Shell,推荐将环境变量放在家目录的".bashrc"文件末尾,例如:
#在当前用户每次打开Bash时都会去读取执行".bashrc"这个文件,就会初始化我们写入的环境变量或命令别名,供当前Bash使用 root@qingsword.com:~# echo website=\"www.qingsword.com\" >> $HOME/.bashrc #查看 root@qingsword.com:~# tail -n 3 $HOME/.bashrc website="www.qingsword.com" #注意!这种方法添加的环境变量,必须要新打开一个Bash时才能生效
0×6.设置PATH环境变量
在Linux中存在一个很特殊的环境变量"PATH",这个环境变量允许用户输入一组目录,当你在Shell中输入一个外部命令时,Shell会自动搜索"PATH"变量值中所有目录来找到对应的程序,在"PATH"变量 中的目录使用冒号分隔,例如:
#在"PATH"变量输出值中可以看到,每个目录都用冒号分隔 root@qingsword.com:~# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin #如果我们想添加自己的程序目录到这个列表中,方便外部程序的调用,可以使用下面的方法,用家目录举例,我们将家目录添加到"PATH"变量值的末尾 root@qingsword.com:~# PATH=$PATH:$HOME root@qingsword.com:~# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root
0×7.设置数组变量
数组变量在Bash中使用的并不多,数组变量的概念与大多数编程语言一样,但处理方式稍有不同,请看下面的实例:
#创建一个数组变量,存储1到5 root@qingsword.com:~# qingsword=(1 2 3 4 5) #如果使用echo输出,仅能输出这个数组变量的第一个值 root@qingsword.com:~# echo $qingsword 1 #如果要输出其他值,需要使用大括号,并在变量末尾添加一个从0开始的索引值 #索引从0开始,对应关系如下 #索引:0 1 2 3 4 #数组:1 2 3 4 5 root@qingsword.com:~# echo ${qingsword[1]} 2 root@qingsword.com:~# echo ${qingsword[3]} 4 #如果要输出数组中所有值,可以使用 通配符星号 root@qingsword.com:~# echo ${qingsword[*]} 1 2 3 4 5 #将索引位置为0的值,改为"www.qingsword.com" root@qingsword.com:~# qingsword[0]=www.qingsword.com #查看变化 root@qingsword.com:~# echo ${qingsword[*]} www.qingsword.com 2 3 4 5 #清除数组中索引为1的位置的值 root@qingsword.com:~# unset qingsword[1] root@qingsword.com:~# echo ${qingsword[*]} www.qingsword.com 3 4 5 #与其他编程语言不同之处,当索引1位置的值被清空后,索引1位置的值就一直保留为空 root@qingsword.com:~# echo ${qingsword[1]} root@qingsword.com:~# echo ${qingsword[2]} 3 root@qingsword.com:~# echo ${qingsword[0]} www.qingsword.com