条件测试和结构化语句

条件测试和结构化语句
条件测试
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
no
if语句的结构
单分支结构
双分支结构
多分支结构
if语句应用示例
单分支if语句
检查httpd服务是否开启
[root@localhost ~]# cat test.sh
#!/bin/bash
If ! service httpd status &> /dev/null
then
           service httpd start
fi
双分支if语句
判断目标主机是否存活,显示检测结果
[root@localhost ~]# cat pinghost.sh
#!/bin/bash
if ping -c 3 -i 0.2 -w 2 $1 &> /dev/null
then
 echo "Host $1 is up."
else
 echo "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
then
 echo "已安装 `rpm -q sysstat`"
else
 echo "未安装,尝试自动安装"
    RHEL_DIR="/media/cdrom/Server/"
 if [ -d $RHEL_DIR ]
 then
 cd $RHEL_DIR
        rpm -ivh sysstat-*.rpm && echo "安装完成。"
 else
 echo "错误:无法访问光盘目录:$RHEL_DIR"
 fi
fi
多分支if语句
判断分数范围,分出优秀、合格、不合格三档
#[root@localhost ~]# cat gradediv.sh   判断分数所在区间,给出不同的分档结果
#!/bin/bash
read -p "请输入您的分数(0-100):" GRADE
if (( $GRADE >= 85 )) && (( $GRADE <= 100 ))
then
 echo "$GRADE 分!优秀"
elif (( $GRADE >= 70 )) && (( $GRADE <= 84 ))
then
 echo "$GRADE 分,合格"
else
 echo "$GRADE 分?不合格”
fi
[root@localhost ~]# ./gradediv.sh
请输入您的分数(0-100):89
89 分!优秀
exit命令
默认情况下shell脚本以脚本中最后一条命令的退出状态退出,exit后的命令不会被执行,马上 退出脚本
  • exit n n是0-255的退出状态数值,不写n默认为0
#!/bin/bash
name=sxkj
if [[ $1 = $name ]]
 then
 echo "不能创建$name这个用户"
 exit 1
 else
 useradd $1 && echo 123 | passwd --stdin $1 &> /dev/null
fi
echo "用户$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/bash
j=$1
for ((i=1; i<=j; i++))
do
 touch file$i && echo file $i is ok
done
for语句应用示例
编写脚本清空所有arp缓存记录
#!/bin/bash
for i in $(arp | tail -n +2 | tr -s ' ' | cut -d' ' -f1)
do
   arp -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/bash
echo "准备倒数5秒"
for i in $(seq 5 -1 1)
do
 echo -en "$i
 sleep 1
done
echo -e "开始"
#!/bin/bash
echo "准备倒数5秒"
for i in $(seq 5 -1 1)
do
 echo -en "$i\b"
 sleep 1
done
echo "开始"
批量添加用户
用户名存放在users.txt文件中,每行一个
[root@localhost ~]# cat uaddfor.sh
#!/bin/bash
ULIST=$(cat /root/users.txt)
for UNAME in $ULIST
do
 useradd $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/bash
dengchao:x:1012:1012::/home/dengchao:/bin/bash
zhangjie:x:1013:1013::/home/zhangjie:/bin/bash
根据位置参数批量添加用户
#!/bin/bash
for i in $@ #可替换成for i
do
 useradd $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 ok
user bb is ok
user cc is ok
user dd is ok
根据IP地址检查主机状态
IP地址存放在ipadds.txt文件中,每行一个
[root@localhost ~]# cat /root/ipadds.txt
192.168.4.11
192.168.4.110
192.168.4.120
[root@localhost ~]# cat chkhosts.sh
#!/bin/bash
HLIST=$(cat /root/ipadds.txt) #从列表文件读取IP地址
for IP in $HLIST
do
 ping -c 2 -i 0.2 -w 1 $IP &> /dev/null
 if (($?==0)) ; then
 echo "Host $IP is up."
 else
 echo "Host $IP is down." #嵌套if语句判断连通性
 fi
done
使用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等循环语句中,用于跳过循环体内余下的语句,重新判断条件以便执行下一次循环
breakcontinue语句应用示例
分析下列两个脚本的显示结果
#!/bin/bash
for i in `seq 6`
do 
if ((i % 2 == 0 ))
then
 break;
fi
echo $i;
done
#!/bin/bash
for i in `seq 6`
do
if ((i % 2 == 0 ))
 then
 continue;
 fi
echo $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 files
bb 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
请输入需要删除的用户名前缀: r
root是系统用户不能删除
rpc是系统用户不能删除
rtkit是系统用户不能删除
rpcuser是系统用户不能删除
用户rr1已经被成功删除
用户rr2已经被成功删除
一共删除的用户数:2个
posted @ 2019-01-22 21:43  DBA_zzher  阅读(345)  评论(0编辑  收藏  举报