学习笔记:CentOS7学习之二十一: 条件测试语句和if流程控制语句的使用
本文用于记录学习体会、心得,兼做笔记使用,方便以后复习总结。内容基本完全参考学神教育教材,图片大多取材自学神教育资料,在此非常感谢MK老师和学神教育的优质教学。希望各位因学习需求而要进行转载时,能申明出处为学神教育,谢谢各位!
假期归来,满血复活,满状态开搞,加油!
21.1 read命令键盘读取变量的值
从键盘读取变量的值,通常用在shell脚本中与用户进行交互的场合。该命令可以一次读取多个变量的值,变量和输入的值都需要使用空格隔开。在read命令后面,如果没有指定变量名,读取的数据将被自动赋值给特定的变量REPLY
read从键盘读入数据,赋给变量
[root@CentOs7_64_1_128 ~]# read a b
aaa bbb
[root@CentOs7_64_1_128 ~]# echo $a
aaa
[root@CentOs7_64_1_128 ~]# echo $b
bbb
21.1.1 read常用见用法及参数
例1:从标准输入读取一行并赋值给变量passwd
[root@CentOs7_64_1_128 ~]# read passwd
112233
[root@CentOs7_64_1_128 ~]# echo $passwd
112233
例2:读取多个值,从标准输入读取一行,直至遇到第一个空白符或换行符。把用户键入的第一个词存到变量first中,把该行的剩余部分保存到变量last中
[root@CentOs7_64_1_128 ~]# read frist last
hello world
[root@CentOs7_64_1_128 ~]# echo $frist$last
helloworld
例3:read -s passwd 将你输入的东西隐藏起来,值赋给passwd。这个用户隐藏密码信息
[root@CentOs7_64_1_128 ~]# read -s passwd
[root@CentOs7_64_1_128 ~]# echo $passwd
334455
例4:输入的时间限制
[root@CentOs7_64_1_128 ~]# read -t 10 passwd
#设置read读取时间为10s,如果超出10s没有输入字符,或者输入字符但是没有输入回车,都会自动推出
[root@CentOs7_64_1_128 ~]# read -t 10 passwd
[root@CentOs7_64_1_128 ~]# echo $? #查看上个程序返回的值为142
142
例5:输入的长度限制
[root@CentOs7_64_1_128 ~]# read -n 5 passwd #设置read读取的字符个数最大为5个
11223[root@CentOs7_64_1_128 ~]# echo $passwd #超过5个字符以后,会自动退出read,并保存变量值为输入的前5个字符
11223
例6:使用-r参数输,允许让输入中的内容包括:空格、/、\、 ?等特殊字符串。
[root@CentOs7_64_1_128 ~]# read -r line #容许输入内容中有特殊字符
112233 ^%$@#$^&*&%()^! 、、、
[root@CentOs7_64_1_128 ~]# echo $line
112233 ^%$@#$^&*&%()^! 、、、
例7:-p 用于给出提示符
方法一:
[root@CentOs7_64_1_128 ~]# read -p "请输入您的信息:" info
请输入您的信息:好的,知道了
[root@CentOs7_64_1_128 ~]# echo $info
好的,知道了
方法二:
[root@CentOs7_64_1_128 ~]# echo -n "请输入您的信息:";read info # echo -n 输出信息后不换行
请输入您的信息:好的,知道了
[root@CentOs7_64_1_128 ~]# echo $info
好的,知道了
例8:read 综合实例
实例1
[root@CentOs7_64_1_128 ~]# read -s -n 3 -t 10 -p "请输入您的年龄:" age
# 设置输入不显示,最多读取3个字符,超时时间为10s
请输入您的年龄:[root@CentOs7_64_1_128 ~]# echo $age
105
实例2
[root@CentOs7_64_1_128 tmp]# vim +14 test1.sh #编辑test1脚本
#!/bin/bash
read -p "请输入你的姓名:" NAME
read -p "请输入您的年龄:" AGE
read -p "请输入您的性别:" SEX
cat<<EOF
*************
您的基本信息如下:
姓名:$NAME
年龄:$AGE
性别:$SEX
*************
EOF
[root@CentOs7_64_1_128 tmp]# bash test1.sh
请输入你的姓名:老杨
请输入您的年龄:32
请输入您的性别:男
*************
您的基本信息如下:
姓名:老杨
年龄:32
性别:男
*************
21.2 流程控制语句if
21.2.1 语法格式:
if 条件;then
commands
fi
注:根据我们的命令退出码来进行判断(echo $? =0),如果是0,那么就会执行then后面的命令
例1:
[root@CentOs7_64_1_128 tmp]# vim if-1.sh
#!/bin/bash
if ls /mnt; then
echo "it's ok"
fi
[root@CentOs7_64_1_128 tmp]# bash if-1.sh
it's ok
21.2.2 双分支if语句
语法格式:
if command ; then
commands
else
commands
fi
例1:
[root@CentOs7_64_1_128 tmp]# vim if-2.sh #在passwd文件中查找root信息,如果有则打印it's ok,即确认root用户是否存在
#!/bin/bash
if grep root /etc/passwd; then
echo "it's ok"
else
echo "it's err"
fi
[root@CentOs7_64_1_128 tmp]# bash if-2.sh
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
it's ok
例2:
[root@CentOs7_64_1_128 tmp]# vim if-3.sh #在passwd文件中查找yg信息,如果有则打印it's ok,即确认yg用户是否存在
#!/bin/bash
if grep yg /etc/passwd; then
echo "it's ok"
else
echo "it's err"
fi
[root@CentOs7_64_1_128 tmp]# bash if-3.sh
it's err
21.2.3 多分支if语句
语法结构:
if条件测试操作1 ; then
commands
elif 条件测试操作2 ; then
commands
elif 条件测试操作3 ; then
commands
.......
else
commands
fi
例1:判断用户在系统中是否存在,是否有家目录
[root@CentOs7_64_1_128 tmp]# vim if-4.sh
#!/bin/bash
read -p "input your username:" tu # 将读取的字符串存入tu
if grep $tu /etc/passwd; then # 查看$tu是否存在
echo "the user $tu exists on the system"
elif ls -d /home/$tu; then # 查看$tu是否有家目录
echo "the user $tu exists on the system"
echo "the user $tu has a directory"
else
echo "the user $tu doesn't exists on the system"
echo "the user $tu doesn't have a directory"
fi
[root@CentOs7_64_1_128 tmp]# bash if-4.sh
input your username:root
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
the user root exists on the system
[root@CentOs7_64_1_128 tmp]# bash if-4.sh
input your username:yangjie
yangjie:x:1000:1000:yangjie:/home/yangjie:/bin/bash
the user yangjie exists on the system
21.3 test测试命令
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试
格式:test 测试条件
如果结果是对的,也叫结果为真,用$?=0表示,反之为假,用非0表示
21.3.1 数值比较
参数 | 说明 | 示例 |
---|---|---|
-eq | 等于则为真 | [ “\(a” -eq “\)b” ] |
-ne | 不等于则为真 | [ “\(a” -ne “\)b” ] |
-gt | 大于则为真 | [ “\(a” -gt “\)b” ] |
-ge | 大于等于则为真 | [ “\(a” -ge “\)b” ] |
-lt | 小于则为真 | [ “\(a” -lt “\)b” ] |
-le | 小于等于则为真 | [ “\(a” -le “\)b” ] |
例1:比较大小
[root@CentOs7_64_1_128 tmp]# vim +12 test2.sh
#!/bin/bash
if test 2 -eq 1 ;then
echo ok
else
echo err
fi
if [ 2 -eq 2 ] ;then
echo ook
else
echo eerr
fi
[root@CentOs7_64_1_128 tmp]# bash test2.sh
err
ook
例2: 比较整数大小
[root@CentOs7_64_1_128 tmp]# vim test3.sh
#!/bin/bash
read -p "请输入要比较的整数1和整数2:" var1 var2
if [ $var1 -gt $var2 ]; then
echo "$var1 > $var2"
elif [ $var1 -lt $var2 ]; then
echo "$var1 < $var2"
else
echo "$var1=$var2"
fi
[root@CentOs7_64_1_128 tmp]# bash test3.sh
请输入要比较的整数1和整数2:10 20
10 < 20
21.3.2 字符串比较
参数 | 说明 | 示例 |
---|---|---|
== | 等于则为真 | [ “\(a” == “\)b” ] |
!= | 不相等则为真 | [ “\(a” != “\)b” ] |
-z | 字符串. 字符串的长度为零则为真 | [ -z “$a” ] |
-n | 字符串 字符串的长度不为空则为真 | [ -n “$a” ] |
str1 > str2 | str1大于str2为真 | [ str1 > str2 ] |
str1 < str2 | str1小于str2为真 | [ str1 < str2 ] |
例1:根据用户名判断是否是超级管理员
[root@CentOs7_64_1_128 tmp]# vim test4.sh
#!/bin/bash
read -p "input your name:" name
if [ $name == "root" ]; then
echo "you are super administator"
else
echo "you are a general user"
fi
[root@CentOs7_64_1_128 tmp]# bash test4.sh
input your name:root
you are super administator
例2:在做字符串大小比较的时候,注意字符串的顺序
- 大于号和小于号必须转义,要不然SHELL会把它当成重定向符号
- 大于和小于它们的顺序和sort排序是不一样的
- 在test比较测试中,它使用的是ASCII顺序,大写字母是小于小写字母的;sort刚好相反
扩展: ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。
[root@CentOs7_64_1_128 tmp]# vim test5.sh
#!/bin/bash
var1=test
var2=Test
if [ $var1 \> $var2 ]; then
echo "$var1 > $var2"
elif [ $var1 \< $var2 ]; then
echo "$var1 < $var2"
else
echo "$var1 = $var2"
fi
[root@CentOs7_64_1_128 tmp]# bash test5.sh
test > Test
21.3.3 文件比较
参数 | .说明 | 示例 |
---|---|---|
-e 文件名. | 如果文件或目录存在则为真 | [ -e file ] |
-r 文件名. | 如果文件存在且可读则为真 | [ -r file ] |
-w 文件名. | 如果文件存在且可写则为真 | [ -w file ] |
-x 文件名. | 如果文件存在且可执行则为真 | [ -x file ] |
-s 文件名 | 如果文件存在且至少有一个字符则为真 | [ -s file ] |
-d 文件名. | 如果文件存在且为目录则为真 | [ -d file ] |
-f 文件名. | 如果文件存在且为普通文件则为真 | [ -f file ] |
-c 文件名. | 如果文件存在且为字符型文件则为真 | [ -c file ] |
-b 文件名. | 如果文件存在且为块特殊文件则为真 | [ -b file ] |
file1 -nt fle2 | 检查file1是否比file2新 | [ file1 -nt file2 ] |
file1 -ot file2 | 检查file1是否比file2旧 | [ file1 -ot file2 ] |
[root@CentOs7_64_1_128 tmp]# vim test6.sh
#!/bin/bash
if [ -e /etc/passwd ];then
echo "ok"
else
echo "err"
fi
[root@CentOs7_64_1_128 tmp]# bash test6.sh
ok
[root@CentOs7_64_1_128 tmp]# test -e /etc/aa.txt && echo ok || echo err
err
# 组合条件的时候,从左往右执行,条件1&&条件2,条件1成立后执行条件2,条件1不成立时不执行条件2. 条件3||条件4当条件3不成立时执行条件4,成立时不执行。 条件1&&条件2||条件3,当条件1成立时执行条件2,条件1不成立时执行条件3
[root@CentOs7_64_1_128 tmp]# test -e /etc/passwd && echo ok || echo err
ok
例:清空日志目录
[root@CentOs7_64_1_128 tmp]# vim test7.sh
#!/bin/bash
sourcefile="/var/log/messages" # 设置源文件为/var/log/messages
desitinationfile="/var/log/mesg.tmp" # 设置目标文件为/var/log/mesg.tmp
if [ $USER != "root" ]; then # 确认用户是否为root用户,不是的话退出脚本
echo "你必须是管理员才能执行脚本"
exit 10
fi
if [ ! -e $sourcefile ]; then # 判断源文件是否存在,不存在则直接退出
echo "日志文件不存在"
exit 12
fi
# 保留最近100行的日志内容
tail -100 $sourcefile > $desitinationfile # 保存源文件的100最后100行到目标文件
# 日志清理
>$sourcefile # 清空源文件
mv $desitinationfile $sourcefile # 改名目标文件为源文件
echo "确认执行脚本" >> $sourcefile
echo "日志清除完毕"
[root@CentOs7_64_1_128 tmp]# bash test7.sh
日志清除完毕
[root@CentOs7_64_1_128 tmp]# tail /var/log/messages
Jul 2 11:25:01 CentOs7_64_1_128 systemd: Started Session 27 of user pcp.
Jul 2 11:25:01 CentOs7_64_1_128 systemd: Removed slice User Slice of pcp.
Jul 2 11:28:01 CentOs7_64_1_128 systemd: Created slice User Slice of pcp.
Jul 2 11:28:01 CentOs7_64_1_128 systemd: Started Session 28 of user pcp.
Jul 2 11:28:01 CentOs7_64_1_128 systemd: Removed slice User Slice of pcp.
Jul 2 11:30:01 CentOs7_64_1_128 systemd: Started Session 29 of user root.
Jul 2 11:30:01 CentOs7_64_1_128 systemd: Created slice User Slice of pcp.
Jul 2 11:30:01 CentOs7_64_1_128 systemd: Started Session 30 of user pcp.
Jul 2 11:30:01 CentOs7_64_1_128 systemd: Removed slice User Slice of pcp.
确认执行脚本
注:退出码 exit ,取值范围是0-255
例: exit 退出bash,并返回一个值
[root@CentOs7_64_1_128 tmp]# ssh root@192.168.87.127 # 远程登陆127
root@192.168.87.127's password:
Last login: Tue Jul 2 11:48:11 2019 from 192.168.87.128
[root@CentOs7_64_2_127 ~]# exit 234 # 退出ssh登录,并返回值234
登出
Connection to 192.168.87.127 closed.
[root@CentOs7_64_1_128 tmp]# echo $?
234
21.4 流程控制过程中复杂条件和通配符
21.4.1 判断第一种:两个条件都为真或有一个为真就执行
if [ 条件判断一 ] && (||) [ 条件判断二 ]; then
命令一
elif [ 条件判断三 ] && (||) [ 条件判断四 ]; then
命令二
else
执行其它
fi
判断第二种
if [条件判断一 -a (-o) 条件判断二 -a (-o) 条件判断三]; then
elif [条件判断三 -a (-o) 条件判断四 ]; then
else
执行其它
fi
判断第三种
if [[条件判断一 && (||) 条件判断二 ]]; then
elif [[ 条件判断三 && (||) 条件判断四 ]]; then
else
执行其它
fi
例1:设置umask
[root@CentOs7_64_1_128 tmp]# vim umask.sh
#!/bin/bash
if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ];then
echo "umask 002"
else
echo "i am root:umask 022"
fi
[root@CentOs7_64_1_128 tmp]# bash umask.sh
i am root:umask 022
[root@CentOs7_64_1_128 tmp]# su - yangjie
[yangjie@CentOs7_64_1_128 tmp]$ bash umask.sh
umask 002
21.4.2 [[ 。。。 ]]和[ 。。。]的区别
[[… ]] 运算符是[… ]运算符的扩充;[[… ]]能够支持 *,< 、>等符号且不需要转义符
[[ 。。。 ]]和[ 。。。]的区别汇总:
- 所有的字符与逻辑运算符直接用“空格”分开,不能连到一起。
- 在[… ]表达式中,常见的> 、<需要加转义符\,大小比较
- 进行逻辑运算符&& 、||比较时;如果用的[ ]符号,则用在外面,如[… ] && [… ] || [ …]如果在[…]里面进行逻辑与或的比较,则用-a、-o进行表示,如[ x = y –a x < z –o x > m ]
- [[… ]] 运算符只是[… ]运算符的扩充;能够支持< 、>符号运算不需要转义符;它还是以字符串比较大小。里面支持逻辑运算符 || 、 && , 不再使用-a 、-o
- [[…]] 用 && 而不是 -a 表示逻辑“与”;用 || 而不是 -o表示逻辑“或”
- [[… ]]可以进行算术扩展,而[ ... ]不可以
- [[...]]能用正则,而[...]不行
- 双括号(( ))用于数学表达式
- 双方括号号[[ ]]用于高级字符串处理,比如“模糊匹配”
例1:
[root@CentOs7_64_1_128 tmp]# if [[ $USER == r* ]];then echo "hello,$USER";else echo $USER not;fi
hello,root
# 注: 在[[]]中的$USER == r*对比时, r* 表示以r开头的任意长度字符串,这样就包括root
[root@CentOs7_64_1_128 tmp]# if [ $USER == r* ];then echo "hello,$USER";else echo $USER not;fi
root not
# 在[]中对比时r* ,就表示两个字符串 r*
20.4.3 shell中的通配符
字符 | 含义 | 实例 |
---|---|---|
* | 匹配 0 或多个字符 | a*b a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如aabcb, axyzb, a012b, ab. |
? | 匹配任意一个字符 | a?b a与b之间必须也只能有一个字符, 可以是任意字符, 如aab, abb, acb, a0b。 |
[list] | 匹配 list 中的任意单一字符 | a[xyz]b a与b之间必须也只能有一个字符, 但只能是 x 或 y 或 z, 如: axb, ayb, azb。 |
[!list] | 匹配 除list 中的任意单一字符 | a[!0-9]b a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如axb, aab, a-b。 |
[c1-c2] | 匹配 c1-c2 中的任意单一字符 | 如:[0-9] [a-z] a[0-9]b 0与9之间必须也只能有一个字符 如a0b, a1b... a9b。 |
{string1,string2,...} | 匹配 sring1 或 string2 (或更多)其一字符串 | a{abc,xyz,123}b a与b之间只能是abc或xyz或123这三个字符串之一。 |
例:
[root@CentOs7_64_1_128 tmp]# ls /etc/*.conf # 查看etc下所有的.conf文件
/etc/asound.conf /etc/host.conf /etc/nfs.conf /etc/slp.conf
/etc/autofs.conf /etc/idmapd.conf /etc/nfsmount.conf /etc/softhsm2.conf
/etc/autofs_ldap_auth.conf /etc/ipsec.conf /etc/nsswitch.conf /etc/sos.conf
/etc/brltty.conf /etc/kdump.conf /etc/ntp.conf /etc/sudo.conf
/etc/cgconfig.conf /etc/krb5.conf /etc/numad.conf /etc/sudo-ldap.conf
/etc/cgrules.conf /etc/ksmtuned.conf /etc/oddjobd.conf /etc/sysctl.conf
/etc/cgsnapshot_blacklist.conf /etc/ld.so.conf /etc/pbm2ppa.conf /etc/tcsd.conf
/etc/chrony.conf /etc/libaudit.conf /etc/pcp.conf /etc/updatedb.conf
/etc/dleyna-server-service.conf /etc/libuser.conf /etc/pnm2ppa.conf /etc/usb_modeswitch.conf
/etc/dnsmasq.conf /etc/locale.conf /etc/radvd.conf /etc/vconsole.conf
/etc/dracut.conf /etc/logrotate.conf /etc/request-key.conf /etc/wvdial.conf
/etc/e2fsck.conf /etc/man_db.conf /etc/resolv.conf /etc/yum.conf
/etc/fprintd.conf /etc/mke2fs.conf /etc/rsyncd.conf
/etc/fuse.conf /etc/mtools.conf /etc/rsyslog.conf
/etc/GeoIP.conf /etc/named.conf /etc/sestatus.conf
[root@CentOs7_64_1_128 tmp]# ls /etc/????.conf # 查看etc下所有的名称为4个字母的.conf文件
/etc/fuse.conf /etc/host.conf /etc/krb5.conf /etc/sudo.conf /etc/tcsd.conf
[root@CentOs7_64_1_128 tmp]# touch a{1,2,3}.txt # 创建 a1,a2,a3.txt文件
[root@CentOs7_64_1_128 tmp]# ll a[123].txt #查看当前目录下的a1,a2,a3.txt文件
-rw-r--r--. 1 root root 0 7月 2 12:30 a1.txt
-rw-r--r--. 1 root root 0 7月 2 12:30 a2.txt
-rw-r--r--. 1 root root 0 7月 2 12:30 a3.txt
[root@CentOs7_64_1_128 tmp]# ll a[13].txt
-rw-r--r--. 1 root root 0 7月 2 12:30 a1.txt
-rw-r--r--. 1 root root 0 7月 2 12:30 a3.txt
[root@CentOs7_64_1_128 tmp]# ll a[1,2,3].txt
-rw-r--r--. 1 root root 0 7月 2 12:30 a1.txt
-rw-r--r--. 1 root root 0 7月 2 12:30 a2.txt
-rw-r--r--. 1 root root 0 7月 2 12:30 a3.txt
21.5 实战-3个shell脚本
21.5.1 编写脚本查看服务运行状态
[root@CentOs7_64_1_128 tmp]# vim status.sh
#!/bin/bash
if [ $# -ge 1 ]; then # 判断运行脚本是否带有参数,如果有将第一个参数,即服务名称传给systemctl status
systemctl status $1 > /dev/null
if [ $? -eq 0 ]; then # 判断前一个命令是否执行成功,执行成功表示运行正常
echo "$1 服务正在运行"
else
systemctl restart $1 # 运行不正常的话,重启服务
fi
else #如果运行脚本没有带有服务名称的话,提示用户正确的使用格式
echo "执行脚本的格式"
echo "sh $0 服务名"
fi
[root@CentOs7_64_1_128 tmp]# bash status.sh httpd
httpd 服务正在运行
21.5.2 根据学生的成绩判断优劣
[root@CentOs7_64_1_128 tmp]# vim chengji.sh
#!/bin/bash
read -p "input your score:" cj
if [ $cj -le 100 ] && [ $cj -ge 86 ]; then
echo "优秀"
elif [ $cj -le 85 ] && [ $cj -ge 71 ]; then
echo "好"
elif [ $cj -le 70 ] && [ $cj -ge 60 ]; then
echo "良好"
elif [ $cj -le 59 ] && [ $cj -ge 0 ]; then
echo "补考"
else
echo "输入的成绩无效,请重新输入一个0到100之间的整数"
fi
[root@CentOs7_64_1_128 tmp]# bash chengji.sh
input your score:89
优秀
[root@CentOs7_64_1_128 tmp]# bash chengji.sh
input your score:102
输入的成绩无效,请重新输入一个0到100之间的整数
21.5.3 每周一晚上3:00 ,备份数据库服务器上webdb库的所有数据到系统的/mysqlbak目录里,使用系统日期做备份文件名。
[root@CentOs7_64_1_128 tmp]# vim mysqlbackup.sh
#!/bin/bash
backupdir="/mysql" # 定义备份文件夹路径
filename=$(date "+%Y%m%d-%H%M") # 使用日期定义备份文件名称
user=root # 定义执行备份用户名
password=123 # 定义执行备份用户名密码
dbname=webdb # 定义执行备份mysql数据库名称
[ -d ${backupdir} ] || mkdir ${backupdir} #查看备份文件夹是否存在,不存在的话创建该文件夹
mysqldump -u{$user} -p${password} --flush-logs ${dbname} > ${backupdir}/${filename}-webdb.sql #执行mysql备份
if [ $? -eq 0 ]; then # 备份执行成功,打印备份完成
echo "备份完成"
fi
find ${backupdir} -mtime +7 -exec rm -rf {} \; #删除七天之前的备份文件
[root@CentOs7_64_1_128 tmp]# bash mysqlbackup.sh #因为本机没有安装mysql数据库因此脚本执行失败
mysqldump: Got error: 2002: "Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)" when
trying to connect
END
2019-7-2 15:39:44