[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