熟练掌握 shell环境变量
shell就是用户与操作系统内核之间的接口,起着协调用户与系统的一致性和在用户与系统之间进行交互的作用。
shell支持具有字符串值的变量。shell变量不需要专门的说明语句,通过赋值语句完成变量说明并予以赋值。在命令行或 shell 脚本文件中使用Sname的形式引用变量name的值。
1.变量的定义和引用
在shell中,变量的赋值格式如下:
name-string
其中,name是变量名,它的值就是string,“=”是赋值符号。变量名是
以字母或下画线开头的字母、数字和下画线字符序列组成的。
通过在变量名(name)前加$字符(如$name)引用变量的值,引用的
结果就是用字符串string代替$name,此过程也称为变量替换。
在定义变量时,若string中包含空格、制表符和换行符,则sting必须用'string 或者"string"的形式,即用单(双)引号将其括起来。双引号内允许变量替换,而单引号内则不可以。
下面给出一个定义和使用shell变量的例子。
//显示字符常量
[ro0t@CentOS7-1 ~]# echo who are you
who are you
[rO0t@CentOS7-1 ~]# echo 'who are you'
who are you
[r00t@CentOS7-1 ~]# echo "who are you"
who are you
[root@CentOS7-1~]#
//由于要输出的字符串中没有特殊字符,所以’’和”"的效果是一样的,不用““但相当于使用了““
[root@CentOS7-1 ~]# echo Je t'aime
>
//由于要使用特殊字符('),
//'不匹配,shel1认为命令行没有结束,回车后会出现系统第二提示符,
//让用户继续输入命令行,按“Ctrl+c”组合键结束
[root@CentOS7-1~]#
//为了解决这个问题,可以使用下面的两种方法[r00t@CentOS7-1 ~]# echo "Je t'aime"
Je t'aime
[root@CentOS7-1 ~]# echo Je t\'aime
2. shell变量的作用域
与程序设计语言中的变量一样,shell变量有其规定的作用范围。shell变量分为局部变和全局变量。
局部变量的作用范围仅限制在其命令行所在的shell或shell脚本文件中。
全局变量的作用范围则包括本shell进程及其所有子进程。
可以使用export 内置命令将局部变量设置为全局变量。
下面给出一个shell变量作用域的例子。
//在当前shel1中定义变量var1
[root@CentOS7-1 ~]# varl=Linux
//在当前shel1中定义变量var2并将其输出
[root@CentOS7-1 ~]# var2=unix
[root@CentOS7-1 ~]#export var2
//引用变量的值
[root@CentOS7-1 ~]# echo $varl
Linux
[root@CentOS7-1 ~]# echo $var2
unix
//显示当前shell的PID
[root@CentOS7-1 ~]# echo $$
2670
[root@CentOS7-1~]#
//调用子 shell
[root@CentOS7-1 ~]# bash
//显示当前shell的PID
[root@CentOS7-1 ~]# echo $$
2709
//由于var1没有被输出,所以在子shell中已无值
[root@CentOS7-1 ~]# echo $varl
//由于var2被输出,所以在子shell中仍有值
[root@CentOS7-1 ~]# echo $var2
unix
//返回主shell,并显示变量的值
[root@CentOS7-1~]# exit
[root@CentOS7-1 ~]# echo $$
2670
[root@CentOS7-1 ~]# echo $varl
Linux
[root@CentOS7-1 ~]# echo $var2
unix
[root@CentOS7-1 ~]#
3.环境变量
环境变量是指由 shell定义和赋初值的 shell变量。shell用环境变量来确定查找路径、注册目录、终端类型、终端名称、用户名等。所有环境变量都是全局变量,并可以由用户重新设置。表7-6列出了一些系统中常用的环境变量。
不同类型的 shell的环境变量有不同的设置方法。在bash中,设置环境变量用set命令,命令的格式是:
set环境变量=变量的值
例如,设置用户的主目录为/home/john,可以用以下命令:
[root@CentOS7-1 ~]# set HOME=/home/john
shell中的环境变量 |
|||
环境变量名 |
说明 |
环境变量名 |
说明 |
EDITOR、FCEDIT |
Bash fc命令的默认编辑器 |
PATH |
Bash寻找可执行文件的搜索路径 |
HISTFILE |
用于存储历史命令的文件 |
PS1 |
命令行的一级提示符 |
HISTSIZE |
历史命令列表的大小 |
PS2 |
命令行的二级提示符 |
HOME |
当前用户的用户目录 |
PWD |
当前工作目录 |
OLDPWD |
前一个工作目录 |
SECONDS |
当前shell开始后所流逝的秒数 |
不加任何参数直接使用set命令可以显示出用户当前所有环境变量的设置,如下所示:
[root@CentOS7-1 ~]# set
BASH=/bin/Bash
BASH_ENV=/root/.bashrc
(略)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bi n/X11
pSl='[\u@\h\W]\S
PS2='>'
SHELL=/bin/Bash
可以看到其中路径PATH的设置为:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bi n/X11
总共有7个目录,Bash会在这些目录中依次搜索用户输入的命令的可执行文件。
在环境变量前面加上$符号,表示引用环境变量的值,例如:
[root@CentOS7-1~]# cd $HOME
上述命令将把目录切换到用户的主目录。
当修改 PATH变量时,例如,将一个路径/tmp加到 PATH变量前,应设置为:
[root@CentOS7-1~]# PATH=/tmp:$PATH
此时,在保存原有PATH路径的基础上进行了添加。shell在执行命令前,会先查找这个目录。
要将环境变量重新设置为系统默认值,可以使用 unset命令。例如,下面的命令用于将当前的语言环境重新设置为默认的英文状态。
[root@CentOS7-1 ~]# unset LANG
4.命令运行的判断依据:;、&&、||
在某些情况下,若想使多条命令一次输入而顺序执行,该如何办呢?有两个选择,一个是通过项目9要介绍的 shell script撰写脚本去执行,一个则是通过下面的介绍来一次输入多重命令。
(1)cmd;cmd(不考虑命令相关性的连续命令执行)。
在某些时候,我们希望可以一次运行多个命令,例如在关机的时候希望可以先运行两次sync同步化写入磁盘后才关机,那么怎么操作呢?
[root@CentOS7-1 ~]# sync; sync; shutdown -h now
在命令与命令中间利用分号(;)来隔开,这样一来,分号前的命令运行完后就会立刻接着运行后面的命令。
我们看下面的例子:要求在某个目录下面创建一个文件。如果该目录存在的话,直接创建这个文件;如果不存在,就不进行创建操作。也就是说这两个命令彼此之间是相关的,前一个命令是否成功地运行与后一个命令是否要运行有关。这就要用到“&&”或“||”。
(2)$?(命令回传值)与“&&”或“||”。
如同上面谈到的,两个命令之间有相依性,而这个相依性主要判断的地方就在于前一个命令运行的结果是否正确。在Linux中若前一个命令运行的结果正碗,则在Linux中会回传二个8?=0的值。那么我们怎么通过这个回传值来判断后续的命令是否要运行呢?这就要用到“&&”及“||”,如表所示。
“&&”及“||”命令的执行情况说明 |
|
命令执行情况 |
说明 |
cmdl && cmd2 |
若cmdl运行完毕且正确运行($?=0),则开始运行cmd2;若cmdl运行完毕且为错误($2≠0),则cmd2不运行 |
cmdl || cmd2 |
若cmdl运行完毕且正确运行(S?=0),则 cmd2不运行;若 cmdl运行完毕且为错误($?≠0),则开始运行cmd2 |
注意:两个&之间是没有空格的,“||”则是按“Shifl+\”组合键的结果。上述的cmdl及cmd2都是命令。现在回到我们刚刚假想的如下情况。
先判断一个目录是否存在。
若存在,则在该目录下面创建一个文件
由于我们尚未介绍“条件判断式(test)”的使用,在这里我们使用1s以及回传值来判断目录是否存在。让我们进行下面的练习。
【例1】使用 1s 查阅目录/tmp/abc 是否存在,若存在,则用touch 创建/tmp/abc/hehe。
[root@CentOS7-1 ~]# ls /tmp/abc &&touch /tmp/abc/hehe
Is: cannot access /tmp/abc: No such file or directory说明找不到该目录,但并没有touch的错误,表示touch并没有运行[root@CentOS7-1 ~]# mkdir /tmp/abc
[root@CentOS7-1~]# ls /tmp/abc && touch /tmp/abc/hehe
[r0ot@CentOS7-1~]# 11 /tmp/abc
total 0
-rw-r--r--. root root 0 Jul 14 22:34 hehe
若/tmp/abc不存在,touch就不会被运行;若/tmp/abc存在,那么touch就会开始运行。在上面的例子中,我们还必须手动自行创建目录,很麻烦。能不能自动判断:没有该目录就创建呢?看下面的例子。
【例2】测试/tmp/abc是否存在,若不存在,则予以创建;若存在,就不做任何事情。
[root@CentOS7-1 ~]#rm -r /tmp/abc
<==先删除此目录以方便测试
[root@CentOS7-1~]# ls /tmp/abc || mkdir /tmp/abc
1s:/tmp/abc:No such file or directory<=真的不存在
[root@CentOS7-1~]# 11 /tmp/abc
Total 0 <==结果出现了,说明运行了mkdir命令
如果你一再重复执行“ls /tmp/abc || mkdir /tmp/abe”,也不会重复出现mkdir的错误。这是因为/tmp/abc已经存在,所以后续的mkdir就不会执行。
再次讨论:如果想要创建/tmp/abc/hehe这个文件,但是并不知道/tmp/abc是否存在,那该如何办呢?
【例3】如果不管/tmp/abc存在与否,都要创建/tmp/abc/hehe文件,怎么办呢?
[root@CentOS7-1-]#ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe
上面的例3总是会创建/tmp/abc/hehe,不论/tmp/abc 是否存在。那么例3应该如何解释呢?由于Linux下面的命令都是由左往右执行的,所以例3有下面两种结果。
若/tmp/abc不存在。回传$?≠0;因为遇到不为0的$?,故开始执行mkdir /tmp/abc,由于 mkdir /tmp/abc会成功执行,所以回传$?=0;因为&&遇到$?=0,故会执行touch/tmp/abc/hehe,最终hehe 就被创建了。
若/tmp/abc存在。回传$?=0;因为||遇到$?=0不会执行,此时$?=0继续向后传;而&&遇到$?=0 就开始创建/tmp/abc/hehe,所以最终/tmp/abc/hehe 被创建。整个流程如图所示。
命令依序运行的关系示意图
上面这张图显示的两股数据中,上方的线段为不存在/tmp/abc时所进行的命令行为,下方的线段则是存在/tmp/abc 时所进行的命令行为。如上所述,下方线段由于存在/tmp/abc所以导致S?=0,中间的mkdir就不运行了,并将$?=0继续往后传给后续的 touch去利用。
我们再来看看下面这个例题。
【例4】以ls测试/tmp/bobbying是否存在:若存在,则显示“exist”;若不存在,则显示“not exist”。
这又牵涉到逻辑判断的问题,如果存在就显示某个数据,如果不存在就显示其他数据,那么我们可以这样做:
ls /tmp/bobbying && echo "exist" || echo "not exist"
意思是说,在 ls /tmp/bobbying运行后,若正确,就运行 echo "exist",若有问题,就运行 echo "not exist”。那如果写成如下的方式又会如何呢?
ls /tmp/bobbying || echo "not exist" && echo "exist"
这其实是有问题的,为什么呢?由图7-2的流程介绍,我们知道命令一个一个往后执行,因此在上面的例子中,如果/tmp/bobbying不存在,会进行如下动作。
①若Is/tmp/bobbying不存在,则回传一个非0的数值。
②接下来经过||的判断,发现前一个命令回传非0的数值,因此,程序开始运行 echo "not exist",而 echo"not exist”程序肯定可以运行成功,因此会回传一个0值给后面的命令。
③经过&&的判断,所以就开始运行 echo "exist"。
这样、在这个例子里面竟然会同时出现not exist 与exist,是不是很有意思啊!请读者仔细思考。
特别提示:经过这个例题的练习,你应该了解,由于命令是一个接着一个运行的,因此,如果真要使用判断,那么&&与||的顺序就不能搞错。一般来说,假设判断式有3个,也就是 commandl && command2|| command3,而且顺序通常不会变。因为一般来说,command2 与command3 会放置肯定可以运行成功的命令,因此,依据上面例题的逻辑分析,必须按此顺序放置各命令,请读者一定注意。
5.工作环境设置文件
shell环境依赖于多个文件的设置。用户并不需要每次登录后都对各种环境变量进行手工设置,通过环境设置文件,用户工作环境的设置可以在登录的时候自动由系统来完成。环境设置文件有两种,一种是系统环境设置文件,另一种是个人环境设置文件。
- 系统中的用户环境设置文件。
登录环境设置文件:/etc/profile。
非登录环境设置文件:/etc/bashrc。
2 .用户设置的环境设置文件。
登录环境设置文件:$HOME/.Bash _profile。
非登录环境设置文件:$HOME/.bashrc。
注意:只有在特定的情况下才读取 profile 文件,确切地说是在用户登录的时候读取。当运行shell脚本以后,就无须再读 profile 文件。
系统中的用户环境设置文件对所有用户均生效,而用户设置的环境设置文件仅对用户自身生效。用户可以修改自己的用户环境设置文件来覆盖系统环境设置文件中的全局设置。例如,用户可以将自定义的环境变量存放在SHOME/.Bash profile 中;将自定义的别名存放在$HOME/.bashrc 中,以便在每次登录和调用子shell时生效。