shell 是一种脚本语言,该语言提供了对linux服务器进行操作的命令集合及逻辑处理方式。
1.shell变量定义
在定义变量时,若string中包含空格、制表符和换行符,则string必须用 'string' 或者 "string"的形式,即用单(双)引号将其括起来。双引号内允许变量替换,而单引号内则不可以。
下面给出一个定义和使用shell变量的例子。
//显示字符常量 [root@RHEL7-1 ~]# echo who are you who are you [root@RHEL7-1 ~]# echo 'who are you' who are you [root@RHEL7-1 ~]# echo "who are you" who are you [root@RHEL7-1 ~]# //由于要输出的字符串中没有特殊字符,所以' '和" "的效果是一样的,不用""但相当于使用了"" [root@RHEL7-1 ~]# echo Je t'aime > //由于要使用特殊字符('), //由于'不匹配,shell认为命令行没有结束,回车后会出现系统第二提示符, //让用户继续输入命令行,按“Ctrl+C”组合键结束 [root@RHEL7-1 ~]# //为了解决这个问题,可以使用下面的两种方法 [root@RHEL7-1 ~]# echo "Je t'aime" Je t’aime [root@RHEL7-1 ~]# echo Je t\'aime
2.shell变量的作用域
与程序设计语言中的变量一样,shell变量也有规定的作用范围。shell变量分为局部变量和全局变量。
- 局部变量的作用范围仅限命令行所在的shell或shell脚本文件中。
- 全局变量的作用范围则包括本shell进程及其所有子程序。
- 可以使用export内置命令将局部变量设置为全局变量。
//在当前shell中定义变量var1 [root@RHEL7-1 ~]# var1=Linux //在当前shell中定义变量var2并将其输出 [root@RHEL7-1 ~]# var2=unix [root@RHEL7-1 ~]# export var2 //引用变量的值 [root@RHEL7-1 ~]# echo $var1 Linux [root@RHEL7-1 ~]# echo $var2 unix //显示当前shell的PID [root@RHEL7-1 ~]# echo $$ 2670 [root@RHEL7-1 ~]# //调用子shell [root@RHEL7-1 ~]# bash //显示当前shell的PID [root@RHEL7-1 ~]# echo $$ 2709 //由于var1没有被输出,所以在子shell中已无值 [root@RHEL7-1 ~]# echo $var1 //由于var2被输出,所以在子shell中仍有值 [root@RHEL7-1 ~]# echo $var2 unix //返回主shell,并显示变量的值 [root@RHEL7-1 ~]# exit [root@RHEL7-1 ~]# echo $$ 2670 [root@RHEL7-1 ~]# echo $var1 Linux [root@RHEL7-1 ~]# echo $var2 unix [root@RHEL7-1 ~]#
3.多命令运行练习
我们有如下情况。
- 先判断一个目录是否存在。
- 若存在,则在该目录下面创建一个文件。
由于我们尚未介绍“条件判断式(test)”的使用,在这里我们使用ls以及回传值来判断目录是否存在。让我们进行下面的练习。
【例7-1】使用ls查阅目录/tmp/abc是否存在,若存在,则用touch创建/tmp/abc/hehe。
[root@RHEL7-1 ~]# ls /tmp/abc && touch /tmp/abc/hehe ls: cannot access /tmp/abc: No such file or directory [root@RHEL7-1 ~]# mkdir /tmp/abc [root@RHEL7-1 ~]# ls /tmp/abc && touch /tmp/abc/hehe [root@RHEL7-1 ~]# ll /tmp/abc total 0 -rw-r--r--. 1 root root 0 Jul 14 22:34 hehe
如果/tmp/abc不存在时,touch就不会被运行;若/tmp/abc存在,那么touch就会开始运行。在上面的例子中,我们还必须手动自行创建目录,很麻烦。能不能自动判断:如果没有该目录就创建呢?看下面的例子。
【例7-2】测试/tmp/abc是否存在,若不存在,则予以创建;若存在,就不做任何事情。
[root@RHEL7-1 ~]# rm -r /tmp/abc // <==先删除此目录以方便测试 [root@RHEL7-1 ~]# ls /tmp/abc || mkdir /tmp/abc ls: /tmp/abc: No such file or directory <==真的不存在 [root@RHEL7-1 ~]# ll /tmp/abc Total 0 // <==结果出现了,说明运行了mkdir命令
如果一再重复“ls /tmp/abc || mkdir /tmp/abc”,也不会出现重复mkdir的错误。这是因为/tmp/abc已经存在,所以后续的mkdir就不会进行。
再次讨论:如果想要创建/tmp/abc/hehe这个文件,但是并不知道 /tmp/abc是否存在,那该如何办呢?
【例7-3】如果不管/tmp/abc存在与否,都要创建/tmp/abc/hehe文件,怎么办呢?
[root@RHEL7-1 ~]#ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe
上面的例7-3总是会创建/tmp/abc/hehe,不论/tmp/abc是否存在。那么例7-3应该如何解释呢?由于Linux下面的命令都是由左往右执行的,所以例7-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所以导致 $?=0,中间的mkdir就不运行了,并将 $?=0继续往后传给后续的touch去利用。
我们再来看看下面这个例题。
【例7-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不存在时,会进行如下动作。
① 若ls /tmp/bobbying不存在,则回传一个非0的数值。
② 接下来经过||的判断,发现前一个命令回传非0的数值,因此,程序开始运行echo "not exist",而echo "not exist" 程序肯定可以运行成功,因此会回传一个0值给后面的命令。
③ 经过&&的判断,所以就开始运行echo "exist"。
这样,在这个例子里面竟然会同时出现not exist与exist,是不是很有意思啊!请读者仔细思考。
特别提示:经过这个例题的练习,你应该了解,由于命令是一个接着一个运行的,因此,如果真要使用判断,那么 && 与 || 的顺序就不能搞错。一般来说,假设判断式有3个,也就是,command1 && command2 || command3,而且顺序通常不会变。因为一般来说,command2与command3会放置肯定可以运行成功的命令,因此,依据上面例题的逻辑分析,必须按此顺序放置各命令,请读者一定注意。