乐清网站推广网络技术开发有限公司
接着上一章继续
- 数值的对比
 - 判断语句
 - 循环语句
 
 22.5 比较、对比、判断 
 
 在写脚本时,有时需要做一些比较,例如,两个数字谁大谁小,两个字符串是否相同等。  
 
 做对比的表达式有[]、[[]]、test,其中[]和 test这两种表达式的作用是相同的。[[]]和[]的不同  
 
 在于,[[]]能识别通配符和正则表达式中的元字符,[]却不能。  
 
 需要注意的是,在比较时,中括号和后续提及的比较符两边都要留有空格。 
 
 
 22.5.1数字的比较  
  数字的比较,主要是比较两个数字谁大谁小,或者是否相同。能用到的比较符有以下几  
  种。  
  (1)-eq:相等。  
  (2)-ne:不相等。  
  (3)-gt:大于。  
  (4)-ge:大于等于。  
  (5)-lt:小于。  
  (6)-le:小于等于。  
  做完比较之后,通过返回值来判断比较是否成立。  
  练习1:判断1等于2,命令如下。 
  [root@pp yy]# [ 1 -eq 2 ]
[root@pp yy]# echo $?
1
[root@pp yy]# 
  1是不能等于2的,所以判断不成立,返回值为非零。注意中括号和比较符两边的空格。  
  练习2:判断1不等于2,命令如下。 
 [root@pp yy]# [ 1 -ne 2 ]
[root@pp yy]# echo $?
0
[root@pp yy]# 
  1不等于2,所以判断成立,返回值为0 
    22.5.2 字待串的比较  
  字符串的比较,一般是比较两个字符串是否相同,用得较多的比较符有以下两种。  
  (1)==:相同。  
  (2)!=:不相同。  
  做完比较之后,通过返回值来判断比较是否成立。  
  练习1:定义一个变量aa=tom,然后做判断,命令如下。 
 [root@pp yy]# aa=tom
[root@pp yy]# [ $aa == tom ]
[root@pp yy]# echo $?
0
[root@pp yy]# 
  变量aa的值和 tom完全相同,所以判断成立,返回值为0。 
  练习2:在判断中匹配通配符,命令如下。 
 [root@pp yy]# aa=tom
[root@pp yy]# [ $aa == to? ]
[root@pp yy]# echo $?
1
[root@pp yy]# 
  这里定义aa=tom,按照前面讲过的通配符,to?匹配的应该是前两个字符为to,第三个  
  可以是任意字符,所以 tom应该会被to?匹配到,为什么返回值为非零呢?  
  原因在于在这一对中括号[]中是不能识别通配符的,aa的值是t、o、m三个字符,而等号  
  后面是t、o、?这三个字符,并没有把问号当成通配符,所以判断不成立。  
  如果想识别通配符,那么就要用双中括号[[]],看下面的判断。  
 [root@pp yy]# aa=tom
[root@pp yy]# [[[ $aa == to? ]]
[root@pp yy]# echo $?
0
[root@pp yy]# 
  在[[]]中能识别通配符“?”,所以这里判断成立,返回值为0。  
  注意  
  (1)==后面跟的是通配符,如果想跟正则表达式,比较符就不能使用==了,要换成=~。  
  (2)一定要注意中括号和比较符两边的空格。  
  22.5.3 属性的判断  
  属性的判断,用于判断一个文件是否具备某个属性,常见的属性包括以下7种。  
  (1)-r:具备读权限。  
  (2)-w:具备写权限。  
  (3)-x:具备可执行权限。 
    注意  
  以上三个属性,不管是出现在u、g还是o上,只要有就算判断成立。  
    ()-d:一个目录。  
  ()-l:一个软链接。  
  ()-f:一个普通文件,且要存在。  
  ()-e:不管什么类型的文件,只要存在就算判断成立。  
  练习1:判断/etc/hosts具备r权限,命令如下。 
 [root@pp yy]# ls -l /etc/hosts 
-rw-r--r--. 1 root root 158 9月  10 2018 /etc/hosts
[root@pp yy]# [ -r /etc/hosts ]
[root@pp yy]# echo $?
0
[root@pp yy]# 
  通过第一条命令可以看到/etc/hosts是具备r权限的,判断/etc/hosts具备r权限,自然成  
  立,所以返回值为0。  
  练习2:判断/etc/hosts具备x权限,命令如下。 
 [root@pp yy]# [ -x /etc/hosts ]
[root@pp yy]# echo $?
1
[root@pp yy]#   22.5.4 使用连接符  
  前面讲的判断只是单个判断,如果要同时做多个判断,那么就需要使用连接符了。能用的  
  连接符包括“&&”和“||”。 
   先看一下使用&&作为连接符,用法如下。 
 1 判断1 && 判断2  只有两个判断都为真(返回值为0),整体才为真,只要有一个为假,整体就为假。判断1  
  如果为假,判断2还有必要执行吗?没有,因为整体已经确定为假了。判断1为真,整体是真  
  是假在于判断2,所以判断2肯定是要执行的。 
 [root@pp yy]# [ 1 -le 2 ] && [ 2 -ge 3 ]
[root@pp yy]# echo $?
1
[root@pp yy]# 
  下面看使用||作为连接符,用法如下。  
   两个判断只要有一个为真(返回值为0),整体就为真,只有全都为假,整体才为假。  
  判断1为真,整体已经确定为真,所以判断2没有必要执行。  
  判断1为假,整体是真是假在于判断2,所以判断2肯定是要执行的。 
 [root@pp yy]# [ 1 -le 2 ] || [ 2 -ge 3 ]
[root@pp yy]# echo $?
0
[root@pp yy]# 
  这里有两个判断,第一个判断是1小于等于2,这个判断成立,整体已经确定为真,所以  
  整个判断为真,返回值为0。 
  22.6 if判断语句  
  在脚本中执行某条命令需要满足一定的条件,如果不满足就不能执行。此时我们就要用到  
  判断语句了。  
  先看if判断,if判断的语法如下。 
 1 if 条件1 ; then
2 命令1
3 elif 条件2 ; then
4 命令2
5 else 命令3
6 fi  先判断if后面的判断是不是成立。  
  如果成立,则执行命令1,然后跳到f后面,执行6后面的命令。  
  如果不成立,则不执行命令1,然后判断elif后面的条件2是不是成立。  
  如果成立,则执行命令2,然后跳到f后面,执行f后面的命令。  
  如果不成立,则不执行命令2,进行下一轮的elif 判断,以此类推。  
  如果所有if和elif都不成立,则执行clse中的命令3。  
  练习1:写一个脚本/opt/sc1.sh,要求只有root用户才能执行此脚本,其他用户不能执  
  行,命令如下。  
 [root@pp opt]# cat sc1.sh 
#/bin/bash
if [ $UID ‐ne 0 ]; then
echo "只有root才能执行此脚本"
exit 1
fi
echo "hello root"
[root@pp opt]# 
[root@pp opt]# chmod +x /opt/sc1.sh 
  脚本分析如下。  
  root的uid是0,其他用户的uid不为0。第一个判断,如果uid不等于0,则打印警告信  
  息“只有root才能执行此脚本”,然后exit退出脚本。  
  如果这里不加 exit,判断之后仍然会继续执行echo "hello root"命令,这样判断就失去  
  了意义。只有加了exit之后,如果不是root,则到此结束,不要继续往下执行了。  
  如果是blab 执行此脚本,则判断成立,打印完警告信息之后,通过exit退出脚本。  
  如果是 root执行此脚本,则判断不成立,直接执行f后面的命令。  
  使用root用户执行此脚本的结果如下。 
 [root@pp opt]# ./sc1.sh 
hello root
[root@pp opt]# 
  使用iu用户执行此脚本的结果如下。 
 [iu@pp opt]$ ./sc1.sh 
只有root才能执行此脚本
[iu@pp opt]$ 
  22.7 for循环语句  
        有时我们需要做多次重复的操作,例如,创建100个用户,创建一个用户需要两条命  
  令:useradd和 passwd。那么,创建100个用户就要重复执行100次,总共执行200条命令,  
  此时我们就可以利用for循环简化操作,让系统自动帮我们重复运行即可。  
          for循环的语法如下。 
  1 for 变量 in 值‐1 值‐2 值‐3 值‐4 ; do
2 命令 $变量
3 done  这里首先把值-1赋值给变量,执行do和done之间的命令,所有命令执行完成之后,再把  
  值-2赋值给变量,执行do和done之间的命令,执行完所有命令之后,再把值-3赋值给变  
  量,以此类推,直到把所有的值都赋值给变量。  
  看一个简单的例子,如下所示。 
 [iu@pp opt]$ for i in 1 2 3 4 ; do
> let i=$i+10
> echo $i
> done
11
12
13
14
[iu@pp opt]$ 
  这里for后面定义了一个变量i,在in后面指定了4个值,分别是1、2、3、4。在do和done  
  之间定义了两个命令,第一个是在变量i的原有值的基础上加上10,然后打印i的值。  
  先把1赋值给i,此时i的值为1,执行do和 done之间的命令。i加上10之后,i的值变为了  
  11,然后打印i,得到11,第一次循环结束。  
  然后把2赋值给i,此时i的值为2,执行do和done之间的命令。i加上10之后,i的值变为了  
  12,然后打印i,得到12,第二次循环结束。 
  22.8 while 循环语句  
   while也可以循环,while循环的语法如下。 
 1 while 判断 ; do
2 命令1
3 命令2
4 done  如果while后面的判断成立,则执行do和 done之间的命令,在最后一个命令执行完成之  
  后,会回头再次判断一下while后面的判断是不是成立。如果不成立,则跳出循环执行done后  
  面的命令;如果成立,则继续执行do和 done之间的命令,就这样循环下去。  
  先看一个简单的例子,写一个脚本/opt/sc3.sh,命令如下。 
 [root@pp opt]# cat sc3.sh 
#!/bin/bash
declare ‐i n=1
while [ $n -le 4 ] ; do
echo $n
let n=$n+1
done
[root@pp opt]# 
[root@pp opt]# chmod +x /opt/sc3.sh   脚本分析如下。  
  这里先通过declare -i n=1定义了一个整数类型的变量n,初始值为1。然后进入 while进  
  行循环,先判断$n的值是不是小于等于4,如果成立,则执行do和 done之间的命令。  
  一开始$n的值为1,[ $n -le 4 ]这个判断成立,则进人 do和done之间执行命令。首先打  
  印Sn的值,然后在此基础上给n 加上1,所以n的值变为了2,这样do和done之间的命令就 执行完成了。然后再次到while后面进行判断,此时$n的值为2,依然满足小于等于4,再次  
  执行do 和 done之间的命令。  
  如此反复,当$n的值最终能增加到4时打印,然后加1,此时n的值变为了5。当Sn的值变  
  为5之后,while后面的判断就不再成立了,此时会跳出 while循环。  
  用while也可以用于循环一个文件的内容,用法如下。 
  1 while read aa ; do
2 命令
3 done < file  这里read后面的变量aa是可以随意指定的,整体的意思是首先读取file的第一行内容赋值  
  给aa,执行do和 done之间的命令。然后读取file的第二行内容赋值给aa,执行do和done  
  之间的命令,直到读取到file的最后一行。  
  有时while需要一直循环下去(死循环),语法如下。 
 1 while true ; do
2 命令
3 done 或
1 while ((1)) ; do
2 命令
3 done 或
1 while : ; do
2 命令
3 done  下面写一个脚本,来实时判断vsftpd是否启动,如果没有启动,则将vsftpd启动,命令如  
  下。 
 [root@pp opt]# cat sc4.sh 
#!/bin/bash
while : ; do
systemctl is‐active vsftpd &> /dev/null
if [ $? -ne 0 ]; then
systemctl start vsftpd
fi
sleep 1
done
[root@pp opt]# 
[root@pp opt]# chmod +x sc4.sh 
  这里写了一个 while循环,可以一直循环下去,循环中先判断vsftpd是否启动,如果启动  
  了则返回值为0,如果没有启动则返回值为非零。  
  下面开始根据返回值来进行判断,如果$?不等于0,说明vsftpd没有启动,则启动vsftpd  
  服务。sleep 1的意思是暂停1秒,这样就实现了每隔1秒来判断一次vsfilpd是否启动。  
  下面开始测试这个脚本,先把脚本放在后台运行,命令如下。 
 [root@pp opt]# ./sc4.sh &
[1] 3788
  测试当前vsftpd 的状态,命令如下。 
 [root@pp opt]# systemctl is‐active vsftpd
active
[root@pp opt]#  关闭vsftpd服务之后,再次检测vsftpd 的状态,命令如下。 
 [root@pp opt]# systemctl stop vsftpd
[root@pp opt]# systemctl is‐active vsftpd
active
[root@pp opt]#  可以看到,vsftpd 仍然是启动的,说明我们的脚本生效了。   
 