Linux用bash写脚本(2)
1.比较、对比、判断
在写脚本时,有时需要做一些比较,例如,两个数字谁大谁小,两个字符串是否相同等。做对比的表达式有[]、[[]]、test,其中[]和 test这两种表达式的作用是相同的。[[]]和[]的不同在于,[[]]能识别通配符和正则表达式中的元字符,[]却不能。
需要注意的是,在比较时,中括号和后续提及的比较符两边都要留有空格。
1.1数字的比较
数字的比较,主要是比较两个数字谁大谁小,或者是否相同。能用到的比较符有以下几种。
1)-eq:相等。
(2)-ne:不相等。
(3)-gt:大于。
(4)-ge:大于等于。
(5)-lt:小于。
(6)-le:小于等于。
做完比较之后,通过返回值来判断比较是否成立
[root@rh1 ~]# [ 1 -eq 2 ]
[root@rh1 ~]# echo $?
1
1是不能等于2的,所以判断不成立,返回值为非零。注意中括号和比较符两边的空格。
判断1不等于2,命令如下。
[root@rh1 ~]# [ 1 -ne 2 ]
[root@rh1 ~]# echo $?
0
1不等于2,所以判断成立,返回值为0。
1.2字符串的比较
字符串的比较,一般是比较两个字符串是否相同,用得较多的比较符有以下两种。
(1)==:相同。
(2)!=:不相同。
做完比较之后,通过返回值来判断比较是否成立。
定义一个变量aa=tom,然后做判断,命令如下。
[root@rh1 ~]# aa=tom
[root@rh1 ~]# [ $aa == tom ]
[root@rh1 ~]# echo $?
0
变量aa的值和 tom完全相同,所以判断成立,返回值为0。
在判断中匹配通配符,命令如下。
[root@rh1 ~]# aa=tom
[root@rh1 ~]# [ $aa == to? ]
[root@rh1 ~]# echo $?
1
这里定义aa=tom,按照前面讲过的通配符,to?匹配的应该是前两个字符为to,第三个可以是任意字符,所以 tom应该会被to?匹配到,为什么返回值为非零呢?
原因在于在这一对中括号[]中是不能识别通配符的,aa的值是t、o、m三个字符,而等号后面是t、o、?这三个字符,并没有把问号当成通配符,所以判断不成立。
如果想识别通配符,那么就要用双中括号[[]],看下面的判断。
[root@rh1 ~]# aa=tom
[root@rh1 ~]# [[ $aa == to? ]]
[root@rh1 ~]# echo $?
0
在[[]]中能识别通配符“?”,所以这里判断成立,返回值为0。
1.3属性的判断
属性的判断,用于判断一个文件是否具备某个属性,常见的属性包括以下7种。
(1)-r:具备读权限。
(2)-w:具备写权限。
(3)-x:具备可执行权限。
以上三个属性,不管是出现在u、g还是o上,只要有就算判断成立。
(4)-d:一个目录。
(5)-l:一个软链接。
(6)-f:一个普通文件,且要存在。
(7)-e:不管什么类型的文件,只要存在就算判断成立。
判断/etc/hosts具备r权限,命令如下。
[root@rh1 ~]# ls -l /etc/hosts
-rw-r--r--. 1 root root 158 9月 10 2018 /etc/hosts
[root@rh1 ~]# [ -r /etc/hosts ]
[root@rh1 ~]# echo $?
0
通过第一条命令可以看到/etc/hosts是具备r权限的,判断/etc/hosts具备r权限,自然成立,所以返回值为0。
判断/etc/hosts具备x权限,命令如下。
[root@rh1 ~]# [ -x /etc/hosts ]
[root@rh1 ~]# echo $?
1
这里判断/etc/hosts具备x权限,但是/etc/hosts不管是u、g还是o都不具备x权限,所以判断不成立,返回值为非零。
如果做一个否定判断,在前面加上叹号“!”即可。
判断/etc/hosts没有x权限,命令如下。
[root@rh1 ~]# [ ! -x /etc/hosts ]
[root@rh1 ~]# echo $?
0
这里判断/etc/hosts没有x权限,判断是成立的,所以返回值为0。
判断/etc是一个普通文件,命令如下。
[root@rh1 ~]# [ -f /etc ]
[root@rh1 ~]# echo $?
1
我们知道/etc是一个目录而不是一个文件,所以这个判断是不成立的,返回值为非零。
判断/etc不管是什么类型的,只判断存在还是不存在,命令如下。
[root@rh1 ~]# [ -e /etc/ ]
[root@rh1 ~]# echo $?
0
这里/etc是存在的目录,-e用于判断存在不存在,不判断文件类型,所以返回值为0。
1.4使用连接符
前面讲的判断只是单个判断,如果要同时做多个判断,那么就需要使用连接符了。能用的连接符包括“&&”和“||”。
先看一下使用&&作为连接符,用法如下。
判断1 && 判断2
只有两个判断都为真(返回值为0),整体才为真,只要有一个为假,整体就为假。判断1如果为假,判断2还有必要执行吗?没有,因为整体已经确定为假了。判断1为真,整体是真是假在于判断2,所以判断2肯定是要执行的。
[root@rh1 ~]# [ 1 -le 2 ] && [ 2 -ge 3 ]
[root@rh1 ~]# echo $?
1
这里有两个判断,第一个判断是1小于等于2,这个判断成立,第二个判断是2大于等于3,这个判断不成立。使用&&作为连接符,需要两边的判断都成立,整体才成立,所以整个判断为假,返回值为非零。
[root@rh1 ~]# [ 1 -le 2 ] && [ 2 -le 3 ]
[root@rh1 ~]# echo $?
0
这里有两个判断,第一个判断是1小于等于2,这个判断成立,第二个判断是2小于等于3,这个判断也成立。使用&&作为连接符,需要两边的判断都成立,整体才成立,所以整个判断为真,返回值为0。
下面看使用||作为连接符,用法如下。
判断1 || 判断2
两个判断只要有一个为真(返回值为0),整体就为真,只有全都为假,整体才为假。
[root@rh1 ~]# [ 1 -ge 2 ] || [ 2 -ge 3 ]
[root@rh1 ~]# echo $?
1
这里有两个判断,第一个判断是1大于等于2,第二个判断是2大于等于3,这两个判断都为假,所以整个判断为假,返回值为非零。
2.if判断语句
在脚本中执行某条命令需要满足一定的条件,如果不满足就不能执行。此时我们就要用到判断语句了。
先看if判断,if判断的语法如下。
if 条件1 ; then
命令1
elif 条件2 ; then
命令2
else 命令3
fi
先判断if后面的判断是不是成立。
如果成立,则执行命令1,然后跳到f后面,执行6后面的命令。
如果不成立,则不执行命令1,然后判断elif后面的条件2是不是成立。
如果成立,则执行命令2,然后跳到f后面,执行f后面的命令。
如果不成立,则不执行命令2,进行下一轮的elif 判断,以此类推。
如果所有if和elif都不成立,则执行clse中的命令3。
写一个脚本/opt/sc1.sh,要求只有root用户才能执行此脚本,其他用户不能执行,命令如下。
[root@rh1 opt]# cat /opt/sc1.sh
#/bin/bash
if [ $UID -ne 0 ]; then
echo "只有root才能执行此脚本"
exit 1
fi
echo "hello root"
[root@rh1 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@rh1 opt]# /opt/sc1.sh
hello root
使用bdqn用户执行此脚本的结果如下。
[bdqn@rh1 ~]$ /opt/sc1.sh
只有root才能执行此脚本
写一个脚本 lopt/sc2.sh,运行脚本时,后面必须跟一个参数,参数是系统中的一个文件。
如果这个文件不存在,则显示该文件不存在;如果存在,则显示该文件的行数,命令如下。
[root@rh1 opt]# cat /opt/sc2.sh
#!/bin/bash
if [ $# -eq 0 ] ; then
echo "脚本后面必须跟一个参数"
exit 1
fi
if [ -f $1 ] ; then
wc -l $1
else
echo "$1不存在"
fi
[root@rh1 opt]# chmod +x /opt/sc2.sh
脚本分析如下。
KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲表示参数的个数,第一个判断中,#的值如果等于0,则说明脚本后面没有跟任何参数,打印“脚本后面必须跟一个参数”,然后退出脚本。
如果后面跟了参数,则第一个判断不成立,然后进行下一个if判断。
第一个参数用$1来表示,[ -f $1 ]用于判断所跟的参数是不是存在,如果存在则执行wc-1 $1命令,如果不存在则执行else 中的命令。
运行脚本,效果如下
[root@rh1 opt]# /opt/sc2.sh
脚本后面必须跟一个参数
这次运行没有跟任何参数,则提示必须跟一个参数。
[root@rh1 opt]# /opt/sc2.sh /etc/hostsxxx
/etc/hostsxxx不存在
这里跟了一个不存在的文件/etc/hostsxxx,脚本提示这个文件不存在。
[root@rh1 opt]# /opt/sc2.sh /etc/hosts
2 /etc/hosts
1命令,如果不存在则执行else 中的命令。
运行脚本,效果如下
[root@rh1 opt]# /opt/sc2.sh
脚本后面必须跟一个参数
这次运行没有跟任何参数,则提示必须跟一个参数。
[root@rh1 opt]# /opt/sc2.sh /etc/hostsxxx
/etc/hostsxxx不存在
这里跟了一个不存在的文件/etc/hostsxxx,脚本提示这个文件不存在。
[root@rh1 opt]# /opt/sc2.sh /etc/hosts
2 /etc/hosts
这次脚本后面跟了一个存在的文件/etc/hosts,脚本会显示该文件的行数,为2行。