条件测试和结构化语句
条件测试和结构化语句
条件测试
if语句
for循环语句
调试:
echo
bash -x
set -x
set +x
set -e 命令行报错就退出shell
条件测试操作
test命令
- 测试特定的表达式是否成立,当条件成立时,测试语句的返回值为0,否则为其他数值
- 格式1:test 条件表达式
- 格式2:[ 条件表达式 ] 至少应有一个空格
常见的测试类型
- 测试文件状态
- 整数值比较
- 字符串比较
- 逻辑测试
文件测试
格式:[ 操作符 文件或目录 ]
常用的测试操作符
- -d:测试是否为目录(Directory)
- -e:测试目录或文件是否存在(Exist)
- -f:测试是否为文件(File)
- -s: 测试文件存在且内容非空(仅有1个空格也是非空)
- -r:测试当前用户是否有权限读取(Read)
- -w:测试当前用户是否有权限写入(Write)
- -x:测试当前用户是否有权限执行(eXcute)
[root@localhost ~]# [ -d /etc/vsftpd ]
[root@localhost ~]# echo $?
0 //返回0表示条件成立
[root@localhost ~]# [ -d /etc/hosts ]
[root@localhost ~]# echo $?
1 //返回1表示条件不成立
[root@localhost ~]# [ -e /media/cdrom ] && echo "YES"
YES //逻辑与,“而且”的意思
整数值比较(传统方法)
- 格式:[ 整数1 操作符 整数2 ]
常用的测试操作符
-eq:等于(Equal)
-ne:不等于(Not Equal)
-gt:大于(Greater Than)
-lt:小于(Lesser Than)
-le:小于或等于(Lesser or Equal)
-ge:大于或等于(Greater or Equal)
[root@localhost ~]# who | wc -l
7[root@localhost ~]# [ $(who | wc -l) -gt 5 ] && echo "Too many." // 用户数是否 > 5
Too many.
[root@localhost ~]# [ $(who | wc -l) -ge 10 ] && echo "> = 10." //用户数是否 >= 10
[root@localhost ~]# FreeCC=$(free -m | grep Mem: | tr -s ‘ ’ |cut -d‘ ’ -f4)
[root@localhost ~]# [ $FreeCC -lt 1024 ] && echo ${FreeCC}MB //空闲内存是否 < 1024MB
864MB
双圆括号整数值比较(推荐方法)
- 格式(( 整数1 操作符 整数2 ))
[root@localhost ~]# (( 10+2 > 10-2 )) && echo ok || echo no
ok[root@localhost ~]# a=10
[root@localhost ~]# ((a>20)) && echo ok || echo no //变量加不加$都可以
no[root@localhost ~]# ((a<20)) && echo ok || echo no
ok[root@localhost ~]# ((a==20)) && echo ok || echo no //注意这里是两个=,一个=是赋值
no[root@localhost ~]# ((a!=20)) && echo ok || echo no ///不等于只能用一个=
ok字符串比较(传统方法)
- 格式1:[ 字符串1 = 字符串2 ]
[ 字符串1 != 字符串2 ]
- 格式2:[ -z 字符串 ]
常用的测试操作符
=:字符串内容相同
!=:字符串内容不同,! 号表示相反的意思
-z:字符串内容为空
-n:字符串非空
[root@localhost ~]# echo $LANG
zh_CN.UTF-8
[root@localhost ~]# [ $LANG != "en.US" ] && echo "Not en.US" //测试当前语言环境
Not en.US
[root@localhost ~]# read -p “是否覆盖现有文件(yes/no)?" ACK
是否覆盖现有文件(yes/no)?yes
[root@localhost ~]# [ $ACK = "yes" ] && echo "覆盖" //测试读入的字符串是否为 yes
覆盖字符串比较时建议加上双引号
[root@localhost ~]# a=123
[root@localhost ~]# [ -z $a ] && echo ok || echo no
no[root@localhost ~]# a=
[root@localhost ~]# [ -z $a ] && echo ok || echo no
ok[root@localhost ~]# [ -n $a ] && echo ok || echo no
ok[root@localhost ~]# [ -n "$a" ] && echo ok || echo no //和预计结果不一致
no[root@localhost ~]# a="abc 123"
[root@localhost ~]# [ -z $a ] && echo ok || echo no
-bash: [: abc: binary operator expected //语法错误
no[root@localhost ~]# [ -z "$a" ] && echo ok || echo no
no[root@localhost ~]# [ "$a" = "abc 123" ] && echo ok || echo no
ok双方括号字符串比较(推荐方法)
- 格式: [ [ 字符串1 = 字符串2 ]]
可以解决变量中带空格的问题
[root@localhost ~]# a="abc 123"
[root@localhost ~]# [ $a = "abc 123" ] && echo ok || echo no
-bash: [: too many arguments
no[root@localhost ~]# [[ $a = "abc 123" ]] && echo ok || echo no
ok双方括号字符串比较(推荐方法)
可以使用通配符
[root@localhost ~]# cat test.sh
#!/bin/bash[[ $1 = ??? ]] && echo ok || echo no //匹配字符是任意三个字符的
[root@localhost ~]# ./test.sh ab
no[root@localhost ~]# ./test.sh abc
ok[root@localhost ~]# cat test.sh
#!/bin/bash
[[ $1 = a* ]] && echo ok || echo no //匹配字符是a开头的
[root@localhost ~]# ./test.sh bbba
no[root@localhost ~]# ./test.sh abb
ok双方括号字符串比较(推荐方法)
可以使用通配符
[root@localhost ~]# cat test.sh
read -s -p "please input password: " pass
[[ $pass = ???* ]] && echo passwd is ok || echo passwd too short
//判断密码的长度至少要3位逻辑测试
- 格式1:[ 表达式1 ] &&或|| [ 表达式2 ] ...
- 格式2:[ 表达式1 -a或-o 表达式2 ] ...
常用的测试操作符
-a或&&:逻辑与,“而且”的意思
前后两个表达式都成立时整个测试结果才为真,否则为假
-o或||:逻辑或,“或者”的意思
操作符两边至少一个为真时,结果为真,否则结果为假
!:逻辑否
当指定的条件不成立时,返回结果为真
[root@localhost ~]# [ -d /etc/passwd -a -f /etc/fstab ] && echo ok || echo no
no[root@localhost ~]# [ -d /etc/passwd -o -f /etc/fstab ] && echo ok || echo no
ok[root@localhost ~]# [ ! -d /etc/passwd ] && echo ok || echo no
ok[root@localhost ~]# (( ! 10 > 5 )) && echo ok || echo no
noif语句的结构
单分支结构
双分支结构
多分支结构
if语句应用示例
单分支if语句
检查httpd服务是否开启
[root@localhost ~]# cat test.sh
#!/bin/bashIf ! service httpd status &> /dev/null
then service httpd startfi双分支if语句
判断目标主机是否存活,显示检测结果
[root@localhost ~]# cat pinghost.sh
#!/bin/bashif ping -c 3 -i 0.2 -w 2 $1 &> /dev/null
thenecho "Host $1 is up."
elseecho "Host $1 is down."
fi[root@localhost ~]# ./pinghost.sh 192.168.4.11
Host 192.168.4.11 is up.
[root@localhost ~]# ./pinghost.sh 192.168.4.13
Host 192.168.4.13 is down.
双分支if语句
#!/bin/bash
if rpm -q sysstat &> /dev/null
thenecho "已安装 `rpm -q sysstat`"
elseecho "未安装,尝试自动安装"
RHEL_DIR="/media/cdrom/Server/"
if [ -d $RHEL_DIR ]
thencd $RHEL_DIR
rpm -ivh sysstat-*.rpm && echo "安装完成。"
elseecho "错误:无法访问光盘目录:$RHEL_DIR"
fifi多分支if语句
判断分数范围,分出优秀、合格、不合格三档
#[root@localhost ~]# cat gradediv.sh 判断分数所在区间,给出不同的分档结果#!/bin/bashread -p "请输入您的分数(0-100):" GRADE
if (( $GRADE >= 85 )) && (( $GRADE <= 100 ))
thenecho "$GRADE 分!优秀"
elif (( $GRADE >= 70 )) && (( $GRADE <= 84 ))
thenecho "$GRADE 分,合格"
elseecho "$GRADE 分?不合格”
fi[root@localhost ~]# ./gradediv.sh
请输入您的分数(0-100):8989 分!优秀exit命令
默认情况下shell脚本以脚本中最后一条命令的退出状态退出,exit后的命令不会被执行,马上 退出脚本
- exit n n是0-255的退出状态数值,不写n默认为0
#!/bin/bashname=sxkj
if [[ $1 = $name ]]
thenecho "不能创建$name这个用户"
exit 1
elseuseradd $1 && echo 123 | passwd --stdin $1 &> /dev/null
fiecho "用户$1已经创造完成"
for语句的结构
已知循环次数
读取不同的变量值,用来逐个执行同一组命令
for语句
- for i in 的各种用法
- for i in "file1" “file2” “file3”
- for i in /boot/*
- for i in /etc/*.conf
- for i in $(seq -w 10)
- for i in {1..10}
- for i in $( ls )
- for I in $(<file)
- for i in “$@” #取所有位置参数,可简写为for i
for语句C语言语法
bash shell支持C式for循环
- for (( i=1; i<10; i++ ))
根据脚本输入的参数创建任意个文件
#!/bin/bashj=$1
for ((i=1; i<=j; i++))
dotouch file$i && echo file $i is ok
donefor语句应用示例
编写脚本清空所有arp缓存记录
#!/bin/bashfor i in $(arp | tail -n +2 | tr -s ' ' | cut -d' ' -f1)
doarp -d $i
done产生十个随机数
[root@localhost ~]# for i in {0..9}; do echo $RANDOM;done
[root@localhost ~]# for i in $( seq 10); do echo $RANDOM;done
倒数5秒
#!/bin/bashecho "准备倒数5秒"
for i in $(seq 5 -1 1)
doecho -en "$i“
sleep 1
doneecho -e "开始"
#!/bin/bashecho "准备倒数5秒"
for i in $(seq 5 -1 1)
doecho -en "$i\b"
sleep 1
doneecho "开始"
批量添加用户
用户名存放在users.txt文件中,每行一个
[root@localhost ~]# cat uaddfor.sh
#!/bin/bashULIST=$(cat /root/users.txt)
for UNAME in $ULIST
douseradd $UNAME
echo "123456" | passwd --stdin $UNAME
done初始密码均设为123456
[root@localhost ~]# ./uaddfor.sh
[root@localhost ~]# tail -3 /etc/passwd
chenye:x:1011:1011::/home/chenye:/bin/bashdengchao:x:1012:1012::/home/dengchao:/bin/bashzhangjie:x:1013:1013::/home/zhangjie:/bin/bash根据位置参数批量添加用户
#!/bin/bashfor i in $@ #可替换成for i
douseradd $i && echo user $i is ok
echo 123456 | passwd --stdin $i &> /dev/null
done[root@localhost ~]# ./myuseradd.sh aa bb cc dd
user aa is okuser bb is okuser cc is okuser dd is ok
根据IP地址检查主机状态
IP地址存放在ipadds.txt文件中,每行一个
[root@localhost ~]# cat /root/ipadds.txt
192.168.4.11192.168.4.110192.168.4.120[root@localhost ~]# cat chkhosts.sh
#!/bin/bashHLIST=$(cat /root/ipadds.txt) #从列表文件读取IP地址
for IP in $HLIST
doping -c 2 -i 0.2 -w 1 $IP &> /dev/null
if (($?==0)) ; then
echo "Host $IP is up."
elseecho "Host $IP is down." #嵌套if语句判断连通性
fidone使用ping命令检测各主机的连通性
[root@localhost ~]# ./chkhosts.sh
Host 192.168.4.11 is up.Host 192.168.4.110 is down.Host 192.168.4.120 is up.循环控制语句
break语句
在for、while、until等循环语句中,用于跳出当前所在的循环体,执行循环体后的语句
continue
在for、while、until等循环语句中,用于跳过循环体内余下的语句,重新判断条件以便执行下一次循环
break和continue语句应用示例
分析下列两个脚本的显示结果
#!/bin/bashfor i in `seq 6`
do if ((i % 2 == 0 ))
thenbreak;
fiecho $i;
done#!/bin/bashfor i in `seq 6`
doif ((i % 2 == 0 ))
thencontinue;
fiecho $i;
done案例
实验案例1
使用条件测试完成下列任务
测试/分区磁盘空间,小于10%,显示“一切正常”,否则显示“当前的磁盘空间是磁盘空间% 警告”
统计当前系统的登陆用户,登陆用户小于3个,显示“一切正常”,否则显示“登陆用户已经有:个数”
测试当前主机eth0的网卡入站和出站流量,只要两个都大于200MiB,就显示“警告”;
当内存空闲空间小于内存的5%时,显示“内存不足”,否则显示“当前空闲内存是:内存空闲数值”
实验案例2
判断内核版本,如果大于2.4,显示“内核版本:版本,否则显示“内核版本太低,无法继续”
检查vsftpd服务是否开启,显示效果如下
[root@localhost ~]# test.sh
警告: vsftpd 服务没有启动,准备启动为 vsftpd 启动 vsftpd: [确定]
[root@localhost ~]# test.sh
监听地址: 0.0.0.0:21进程PID: 10478[root@localhost ~]# yum remove vsftpd
[root@localhost ~]# test.sh
vsftpd服务不存在实验案例3
数字范围识别,输入整数得分判断分数范围
90分到100分显示成绩优秀
61分到89分显示成绩合格
60分显示及格万岁
60分以下显示你需要补考
大于100分小于0分显示输入错误
[root@localhost test]# ./test.sh 78
成绩合格[root@localhost test]# ./test.sh 93
成绩优秀[root@localhost test]# ./test.sh 101
输入错误,请输入0-100间的整数[root@localhost test]# ./test.sh 60
及格万岁[root@localhost test]# ./test.sh 31
你需要补考实验案例4
编写我是歌手脚本
要求判断名单文件是否存在
显示效果如下
[root@localhost test]# bash lucky.sh
欢迎来到我是歌手第2季,还有3位参赛歌手,请按任意键开始选择****这次为大家献唱的是谁呢?我们一起倒数3秒钟****3 2 1 会是谁呢?有请歌手‘丝丝'登台还有位2位歌手,下次又会是谁呢,O(∩_∩)O哈哈~
[root@localhost test3]# bash lucky.sh
欢迎来到我是歌手第2季,还有2位参赛歌手,请按任意键开始选择****这次为大家献唱的是谁呢?我们一起倒数3秒钟****3 2 1 会是谁呢?有请歌手‘龙龙'登台只剩下1位压轴歌手啦,万众瞩目的一天就要来到了,(*^__^*) 嘻嘻……
[root@localhost test3]# bash lucky.sh
没得选了,就是有歌坛赵本山之称的‘安安'啦,我是歌手下季将重新开始哦实验案例4
编写脚本利用for循环显示出相应的位置参数。
[root@localhost ~]# ./test.sh 11
脚本有1个参数$1 is 11
[root@localhost ~]# ./test.sh aa bb
脚本有2个参数$1 is aa
$2 is bb
[root@localhost ~]# ./test.sh aa bb cc
脚本有3个参数$1 is aa
$2 is bb
$3 is cc
[root@localhost ~]# ./test.sh
脚本没有接参数实验案例5
查找用户的PATH环境变量中每个目录下有多少个文件
要求判断目录是否存在
[root@localhost ~]# ./test.sh
/usr/lib/qt-3.3/bin - 0
/usr/local/sbin - 0
/usr/local/bin - 0
/sbin - 269
/bin - 111
/usr/sbin - 317
/usr/bin - 1411
/root/bin is not exist
实验案例6
查找UID大于等于500小于等于60000的用户,检查他们在“/tmp”目录中拥有的子目录或文件数量,如果超过10个,则列出具体个数及对应的用户帐号
[root@localhost ~]# ./test.sh
aa have 41 filesbb have 110 files编写脚本统计1000以内个位是十位2倍的数字的个数(例如24)
实验案例7
统计/usr/share/doc目录下所有后缀名是png文件的占用空间总和。
利用for循环实现累加,显示效果如下图所示
[root@localhost ~]# ./test.sh
all png files total size is 2540k计算1000以内所有偶数的总和
建议使用for循环
实验案例9
编写add.sh脚本实现批量创建帐户,脚本要求如下:
提示输入用户名前缀和用户数目
每次创建的用户最多只能是10个,超过10个用户,就不要新建用户并且要报警显示“最多只能同时新建10个用户”然后退出脚本
每新建一个用户,就显示“新用户用户名创建成功”。如果新建用户失败,就显示“新用户用户名创建失败”。密码123最后要显示新建的用户总数是“一共新建的用户数:数目”
[root@servera ~]# bash add.sh
请输入用户名的前缀: stu请输入用户的数目: 15最多只能同时新建10个用户[root@servera ~]# bash add.sh
请输入用户名的前缀: sxkj请输入用户的数目: 2用户sxkj1已经创建成功用户sxkj2已经创建成功一共创建的用户数:2个实验案例10
编写del.sh脚本实现批量删除用户,脚本要求如下:
提示输入需要删除的用户名前缀,如果用户名前缀为空或者空格,就显示“请输入合法用户名前缀”,然后退出脚本,每删除一个用户,要显示“用户用户名 已经成功被删除”。如果没有可以删除的用户,就显示“以用户前缀开头的用户不存在”。最后要显示删除的用户总数是“一共删除的用户数:数目”
注意不能删除管理员或者系统用户(UID小500或者大于60000)
[root@servera ~]# add.sh
请输入用户名的前缀: rr请输入用户的数目: 2用户rr1已经创建成功用户rr2已经创建成功一共创建的用户数:2个[root@servera ~]# del.sh
请输入需要删除的用户名前缀:请输入合法的用户名前缀[root@servera ~]# del.sh
请输入需要删除的用户名前缀:请输入合法的用户名前缀[root@servera ~]# del.sh
请输入需要删除的用户名前缀: rroot是系统用户不能删除rpc是系统用户不能删除rtkit是系统用户不能删除rpcuser是系统用户不能删除用户rr1已经被成功删除用户rr2已经被成功删除一共删除的用户数:2个

浙公网安备 33010602011771号