shell脚本中的if语句、shell脚本中的if条件语句介绍和使用案例(非常全面)
文章目录
- 一、if语法
- 1.1、if单分支结构
- 1.2、双分支结构:加一个else否则
- 1.3、多分支结构
- 1.4、case条件语句
- 二、条件表达式
- 2.1、基本算术运算符
- 2.2、基本比较运算符
- 2.3、关系运算符(整数比较)
- 2.4、字符串比较运算符(字符串需要加引号)
- 2.5、文件比较与检查(-f -d -e … )
- 2.6、逻辑运算符
- 三、test、[ ]、[[ ]]、(())
- 3.1、test、[ ]
- 3.2、[[ ]]
- 3.3、(( ))
- 3.4、不同符号测试表达式[ ]、[[ ]]、(( ))、test的区别
- 四、测试案例
- 4.1、对数字进行判断
- 4.2、a>b且a<c
- 4.3、判断目录是否存在,不存在则创建
- 4.4、练习2
- 4.5、检查软件包是否安装
- 4.6、监控httpd服务
- 4.7、监控mysql服务
- 4.8、网络运算符
一、if语法
1.1、if单分支结构
语法结构:
if <条件表达式>then指令
fi
或者
# 注意:在shell中,then和if是分开的语句。如果要在同一行里面输入,则需要用分号将他们隔开。if <条件表达式>;then指令
fi
if单分支嵌套语句:
if <条件表达式>thenif <条件表达式>thenfi
fi
注意:在shell中,then和fi是分开的语句。如果要在同一行里面输入,则需要用分号将他们隔开。
说明:<条件表达式> 可以是test、[]、[[]]、(())等条件表达式,每一个if条件语句都是以if开头,并带有then,最后以fi结尾
条件表达式可参考:《shell脚本中test、[]、[[]]、(())的区别》
示例
[root@shell]# cat if.sh
#!/bin/bashif [ -f /etc/hosts ]thenecho "[test1]"
fiif [[ -f /etc/hosts ]];thenecho "[[test2]]"
fiif test -f /etc/hoststhenecho "test3"
fi
#说明:上面都是判断/etc/hosts是否是文件并是否存在,如果是文件并且存在就打印相关的命令
# -f :判断后面的是否是个文件
执行效果:
[root@shell]# sh if.sh
[test1]
[[test2]]
test3
1.2、双分支结构:加一个else否则
#if单分支结构主体是:如果…那么…。而双分支结构就是:如果…那么…否则
#语法结构
if <条件表达式>then命令集1else命令集2
fi
示例
[root@shell]# cat if1.sh
#!/bin/bashif [ -f /etc/hosts ]thenecho "is file"elseecho "no file"
fi
#执行效果
[root@shell]# sh if1.sh
is file
1.3、多分支结构
语法结构:
if <条件表达式1>then指令集1elif <条件表达式2>then指令集2elif <条件表达式3> then指令集3 else指令集4
fi
或者
#多分支结构
if <条件表达式1>;then指令集1
elif <条件表达式2>;then指令集2
elif <条件表达式3>;then指令集3
else指令集4
fi
提示:如果加elif,那么就要加then,每个elif都要带有then,最后结尾的else后面没有then
示例:
[root@shell scripts]# cat if2.sh
#!/bin/bashif [ $1 -eq 1 ]thenecho "input 1 success"elif [ $1 -eq 2 ]thenecho "input 2 success "elif [ $1 -eq 3 ]thenecho "input 3 success"elseecho "input failure"
fi
说明:如果传入的第一个参数为1就输出相关命令,或者有如果传入的第一个参数为2,就输出相关命令,后面同理,最后是否则又输出什么
执行效果:
[root@shell]# sh if2.sh 1
input 1 success
[root@shell]# sh if2.sh 2
input 2 success
[root@shell]# sh if2.sh 3
input 3 success
[root@shell]# sh if2.sh 4
input failure
if使用注意项:
- [ ]表示条件测试。注意这里的空格很重要。要注意在’[‘后面和’]'前面都必须要有空格
- 在shell中,if和then是分开的语句。如果要在同一行里面输入,则需要用分号将他们隔开。
- 注意if判断中对于变量的处理,需要加引号,以免一些不必要的错误。没有加双引号会在一些含空格等的字符串变量判断的时候产生错误。比如[ -n “$var” ]如果var为空会出错
- 判断是不支持浮点值的
- 如果只单独使用>或者<号,系统会认为是输出或者输入重定向,虽然结果显示正确,但是其实是错误的,因此要对这些符号进行转意
- 在默认中,运行if语句中的命令所产生的错误信息仍然出现在脚本的输出结果中
- 使用-z或者-n来检查长度的时候,没有定义的变量也为0
- 空变量和没有初始化的变量可能会对shell脚本测试产生灾难性的影响,因此在不确定变量的内容的时候,在测试号前使用-n或者-z测试一下
- ? 变量包含了之前执行命令的退出状态(最近完成的前台进程)(可以用于检测退出状态)
1.4、case条件语句
语法如下:
case $变量名 in “值1”)如果$变量等于值1,则执行程序1 ;;“值2”)如果$变量等于值2,则执行程序2 ;; ....省略... *)如果$变量的值不是以上值,则执行此程序 ;;
esac
4.1举例:创建启动脚本,让service命令管理apache
[root@xiaopeng htdocs]# vim /etc/init.d/apached
#!/bin/bash
# chkconfig: 2345 64 36
# description: A very fast and reliable SQL database engine
httpd=/usr/local/apache2/bin/apachectl
case $1 in
start)$httpd start;;
stop)$httpd stop;;
restart)$0 stop sleep 0.05 $0 start;;
configtest)
$httpd -t
;;
*)echo "usage:$0 start|stop|restart|configtest.";;
esac
4.2举例:创建启动脚本,让service命令管理nginx
[root@xiaopeng conf]# vim /etc/init.d/nginx
#!/bin/bash
#chkconfig: 2345 99 33
#description: nginx server control toolsngxc="/usr/local/nginx/sbin/nginx"
ngxc_fpm="/usr/local/php/sbin/php-fpm"
case "$1" instart)$ngxc -t &> /dev/nullif [ $? -eq 0 ];then$ngxc$ngxc_fpmecho "nginx service start success!"else$ngxc -tfi;;stop)$ngxc -s stopkillall php-fpmecho "nginx service stop success!";;restart)$0 stop$0 start;;reload)$ngxc -t &> /dev/nullif [ $? -eq 0 ];then$ngxc -s reloadpkill -HUP php-fpmecho "reload nginx config success!"else$ngxc -tfi;;*)echo "please input stop|start|restart|reload."exit 1
esac
二、条件表达式
以下整理一下上述语法中<条件表达式>中会用到的一些运算符
2.1、基本算术运算符
加(+)、减(-)、乘(*)、除(/)、取余(%)
原生bash不支持简单的算术运算,可以通过
awk
和expr 表达式
或$(( 表达式 ))
以及let
或(())
#!/bin/bash
# 示例:expr表达式
v1=`expr 2 + 2`
echo "两数之和:$v1" # 两数之和:4# 示例:$(())
v2=$((2 + 2))
echo "两数之和:$v2" # 两数之和:4((c=2 + 4))
echo "两数之和:$c" # 两数之和:6# 示例:let
let v3=1+2
echo "两数之和:$v3" # 两数之和:3#示例:expr表达式为乘,则需要转义
v4=`expr 2 \* 2`
echo "两数乘积:$v4" # 两数乘积:4
注意:
- expr前面是是
反引号
(Esc下面的键),不是单引号 - let 变量符号两侧不能有空格
- expr表达式中
*
需要转义
2.2、基本比较运算符
大于( >) 、大于等于(>=) 、 小于(<)、 小于等于(<=)、 等于(==) 、 不等(!=)
特注:
大于( >) 、大于等于(>=) 、 小于(<)、小于等于(<=) 只能在(())算术运算语法结构中使用。
等于(==) 、 不等(!=) 可以使用expr表达式、(()) 、[ ]运算符
示例:等于(==) 、 不等(!=)
v1=`expr 6 == 6 `
echo "两数相等:$v1" # 两数相等:1v2=`expr 6 != 6 `
echo "两数不相等:$v2" # 两数不相等:0num=3
# 使用$(()))
if (( $num == 3 ))
thenecho "num is 3"
fi# 使用[]运算符
if [ $num == 3 ]
thenecho "结果为:true"
fi
示例: 大于( >) 、大于等于(>=) 、 小于(<)、 小于等于(<=)
num=3
if (( $num <= 5 ))
then echo "$num <= 5" #输出:3 <= 5
else echo "error"
fi# 演示错误:使用 [ ] 表示 数值大于<关系
if [ $num < 5 ]
then echo "$num < 5"
else echo "error"
fi
报错,原因:[ ] 将 < 当作输入符,
op.sh: line 9: 5: No such file or directory
error
问:那如果想使用 [] 表达式表示数值关系呢? 看下文 ===》2.3、关系运算符
2.3、关系运算符(整数比较)
两个整数之间的判定,只支持数字,不支持字符串,除非字符串的值是数字。支持正负数,但不支持小数。例如test n1 -eq n2
比较符,在[] 中使用 | 比较符,在(())或[[]] 中使用,双重括号 | 说明 | 示例 |
---|---|---|---|
-eq | = 或 == | equal的缩写,相等 | [ 1 -eq 10 ] |
-ne | != | not equal的缩写,不相等 | [ 1 -ne 10 ] |
-gt | > | greater than,大于 | [ 1 -gt 10 ] |
-ge | >= | greater ,equal,大于等于 | [ 1 -ge 10 ] |
-lt | < | less than,小于 | [ 1 -lt 10 ] |
-le | <= | less,equal,小于等于 | [ 1 -le 10 ] |
- “=”和“!=”也可在[]中做比较使用,但在[]中使用包含“>”和“<”的符号时,需要用反斜线转义,有时不转义虽然语法不会报错,但是结果可能会不对。
- 也可以在[[]]中使用包含“-gt”和“-lt”的符号,但是不建议这样使用。
- 比较符号连段也要有空格。
示例:
num=3
# 使用[]运算符 -eq 关系运算符
if [ $num -eq 3 ]
thenecho "结果为:true"
fi
2.4、字符串比较运算符(字符串需要加引号)
比较字符 | 含义 |
---|---|
==(等同于=) | 相等 |
!= | 不等 |
-n | 检查字符串长度是否大于0 |
-z | 检查字符串长度是否为0 |
$ | 检查字符串是否不为空,不为空返回true (全是空格也认为是空) |
< | 检查字符串1是否按字典顺序小于字符串2 |
> | 检查字符串1是否按字典顺序大于字符串2 |
示例:
# = 相等
if [ "aa" = "aa" ]
thenecho "aa is ok"
fi# != 不等
if [ "Aa" != "aa" ]
then echo "Aa != aa is ok"
fi# 区分大小写
if [ "Aa" = "aa" ]
then echo "Aa = aa "
elseecho "Aa != aa " # 输出: Aa != aa
fi# -z 检查长度是否为0
str="aa"
if [ -z $str ]
thenecho "长度为0"
elseecho "长度为:${#str}" # 长度为:2
fi# -n 检查长度不为0
str="aa"
if [ -n $str ]
thenecho "长度不为0,长度为:${#str}" # 长度不为0,长度为:2
elseecho "长度为0"
fi# $判断字符串是否为空
name=""
if [ $name ]
thenecho "名称不为空"
elseecho "名称为空,长度为:${#name}" # 名称为空,长度为:0
fi# $判断字符串是否为空、测试3个空格,当全是空格时$也认为是空
name=" "
if [ $name ]
thenecho "名称不为空"
elseecho "名称为空,输出长度为:${#name}" # 名称为空,输出长度为:3
finame="FAN"
if [ $name ]
thenecho "名称不为空" # 名称不为空
elseecho "名称为空"
fi# < 检查第一个字符串是否按字典顺序小于第二个字符串
if [ "abc" < "abb" ]
thenecho "abc 小于 abb"
elseecho "abc 大于 abb" # 输出: abc 大于 abb
fi
2.5、文件比较与检查(-f -d -e … )
以下为常用的几种文件比较参数,还有一些不常用的此处不整理。
文件比较运算符 | 含义 | 示例 |
---|---|---|
-e file | 如果文件或目录存在,则为真 | [ -e /var/log/syslog ] |
-d file | 如果文件存在且为目录,则为真 | [ -d /tmp/mydir ] |
-f file | 如果文件存在且为文件,则为真 | [ -f /usr/bin/grep ] |
-L file | 如果文件存在文件为符号链接,则为真 | [ -L /usr/bin/grep ] |
-r file | 如果文件存在文件且可读,则为真 | [ -r /var/log/syslog ] |
-w file | 如果文件存在文件且可写,则为真 | [ -w /var/mytmp.txt ] |
-x file | 如果文件存在且为可执行文件,则为真 | [ -x /usr/bin/grep.sh ] |
file1 -nt file2 | 如果文件1比 文件2 新,则为真 | [ /tmp/etc/services -nt /etc/services ] |
file1 -ot file2 | 如果文件1 比文件2 旧,则为真 | [ /boot/bzImage -ot arch/boot/bzImage ] |
示例:
file=/data/op.sh
if [ -f $file ]
thenecho "普通文件"
fidir=/data
if [ -d $dir ]
thenecho "目录存在"
fiif [ -e $file ]
then echo "文件或目录存在"
fiif [ -r $file ]
thenecho "文件可读"
fiif [ -w $file ]
thenecho "文件可写"
fiif [ -x $file ]
thenecho "文件可执行"
elseecho "文件不可执行"
fi
# 添加执行权限之前
> ls -l op.sh
-rw-r--r-- 1 my my 639 10 9 20:05 op.sh
> sh file.sh
输出:文件不可执行# 添加执行权限之后
> chmod +x op.sh
> ls -l op.sh
-rwxr-xr-x 1 my my 639 10 9 20:05 op.sh
> sh file.sh
输出:文件可执行# 使用ls -l命令获取文件大小
file_size=$(ls -l "$file" | awk '{print $5}')
if [ -s $file ]
thenecho "文件大小:$file_size 字节" # 文件大小:639 字节
fi
2.6、逻辑运算符
在[ ] 和test中使用的操作符 | 在(( ))和[[ ]]中使用的操作符 | 说明 |
---|---|---|
-a | && | and,与 |
-o | || | or,或 |
! | ! | not,非 |
逻辑操作符前后的表达式是否成立,一般用真假来表示。
- “!”的中文意思是反,即与一个逻辑值相反的逻辑值。
- -a的中文意思是“与”,前后两个逻辑值都为“真”,综合返回值才为“真”,反之为“假”。
- -o的中文意思是“或”,前后连个逻辑值只要有一个为“真”,返回值就为“真”。
- 连接两含[ ]、test或[[ ]]的表达式可用 && 或 ||
1、与(&&) 和 或( || )
注:推荐使用, 第一个条件执行成功后,再执行第二条,,任何一个条件失败,表达式直接返回false
if [[ 1 -lt 2 && 3 -lt 4 ]]
thenecho "ok"
fi
注:此处使用 [[表达式]]
2、与(-a)、或(-o)
注:输入非标准扩展,可能存在兼容性问题,所有条件执行完,表达式才会返回
if [ 1 -lt 2 -a 3 -lt 4 ]
thenecho "ok"
fiif [ -n "$var1" -a -n "$var2" ]; thenecho "所有变量长度都大于0"
fi
3、非(!)
echo "请输入一个字符串:"
read s
if [ ! $s = "a" ]
thenecho "输入的字符串不是a "
else echo "输入的字符是:$s"
fi#测试 输入a
请输入一个字符串:
a
输入的字符是:a#测试 输入q
请输入一个字符串:
q
输入的字符串不是a
三、test、[ ]、[[ ]]、(())
我们在shell脚本中经常能看到test、[]、[[]]、(())这几种写法,那么这几种写法有什么区别呢?怎样正确使用这几种写法呢?一起来看一下吧。
更多内容参考《shell脚本中test、[]、[[]]、(())、$()、“ “、‘ ‘ 的区别》
3.1、test、[ ]
test等同于[ ],[ ]是test的简写方式,所以两者的效果是一致的。
注意:
- [ ]表示条件测试。注意这里的空格很重要。要注意在’[‘后面和’]'前面都必须要有空格
- test与[ ] 支持
2.3关系运算符
、2.4字符串比较运算符
、2.5文件比较与检查
、2.6逻辑运算符中的与(-a)、或(-o)、非(!)
#1:判断目录$home是否存在,若不存在,则新建一个
if [ ! -d "$home" ]; thenmkdir "$home"
fi
3.2、[[ ]]
3.3、(( ))
(( ))
支持2.1基本算术运算符
、2.2、基本比较运算符
#!/bin/bash
# 示例:$(())
v2=$((2 + 2))
echo "两数之和:$v2" # 两数之和:4((c=2 + 4))
echo "两数之和:$c" # 两数之和:6num=3
# 使用$(()))
if (( $num == 3 ))
thenecho "num is 3"
fiif (( $num <= 5 ))
then echo "$num <= 5" #输出:3 <= 5
else echo "error"
fi
3.4、不同符号测试表达式[ ]、[[ ]]、(( ))、test的区别
测试表达式符号 | [ ] | test | [[ ]] | (( )) |
---|---|---|---|---|
边界是否需要空格 | 需要 | 需要 | 需要 | 不需要,有空格不报错 |
逻辑操作符 | -a、-o、! | -a、-o、! | &&、||、! | &&、||、! |
整数比较操作符 | -eq、-gt、-ge、-lt、-le | -eq、-gt、-ge、-lt、-le | -eq、-gt、-ge、-lt、-le或=、>、>=、<、<= | =、>、>=、<、<= |
字符串比较操作符 | =、==、!= | =、==、!= | =、==、!= | =、==、!= |
是否支持通配符匹配 | 支持 |
四、测试案例
4.1、对数字进行判断
输入成绩,判断及格或优秀
#需求1:输入成绩,显示及格优秀
[root@manage if]# cat var02.sh
#!/bin/bash
read -p "成绩查询入口,请输入你的成绩:" cjif [ $cj -lt 60 ];thenecho "成绩不及格......."
elif [ $cj -gt 80 ];thenecho "成绩优秀........."
elseecho "要好好学习......."
fi[root@manage if]# sh +x var02.sh
成绩查询入口,请输入你的成绩:56
成绩不及格.......
[root@manage if]# sh +x var02.sh
成绩查询入口,请输入你的成绩:88
成绩优秀.........
[root@manage if]# sh +x var02.sh
成绩查询入口,请输入你的成绩:70
要好好学习.......
4.2、a>b且a<c
(( a > b )) && (( a < c ))
[[ $a > $b ]] && [[ $a < $c ]]
[ $a -gt $b -a $a -lt $c ]
4.3、判断目录是否存在,不存在则创建
#!/bin/bash
#date:2022-4-13
#描述:if单分支语句示例,判断目录是否存在
read -p "请输入需要判断的目录:" name
if [ ! -d $name ]thenecho "$name目录不存在,正在创建..."mkdir -p $nameecho "$name目录创建完成."
fiecho "$name目录已存在,正在退出..."
4.4、练习2
#需求2:根据输入一个用户名称, read $1 <--test1.判断输入的用户是否存在当前系统,2.如不在再次判断用户是否在/home下拥有家目录3.如果都没有则提示不存在。#方法1:
[root@manage if]# cat var03.sh
#!/bin/bash
if grep $1 /etc/passwd &>/dev/null;thenecho "$1用户存在于系统中"
elif ls -ld /home/$1 &>/dev/null;thenecho "$1用户不存在于系统中,但有家目录"
elseecho "$1用户不存在系统中,也没有家目录"
fi[root@manage if]# useradd ttt
[root@manage if]# sh -x var03.sh ttt
+ grep ttt /etc/passwd
+ echo ttt用户存在于系统中
ttt用户存在于系统中
[root@manage if]# userdel ttt
[root@manage if]# sh -x var03.sh ttt
+ grep ttt /etc/passwd
+ ls -ld /home/ttt
+ echo ttt用户不存在于系统中,但有家目录
ttt用户不存在于系统中,但有家目录
[root@manage if]# rm -rf /home/ttt/
[root@manage if]# sh -x var03.sh ttt
+ grep ttt /etc/passwd
+ ls -ld /home/ttt
+ echo ttt用户不存在系统中,也没有家目录
ttt用户不存在系统中,也没有家目录#方法2:
[root@manage if]# cat var03.sh
#!/bin/bash
grep_user=$(grep $1 /etc/passwd &>/dev/null)
grep_rc=$?cat_dir=$(ls -ld /home/$1 &>/dev/null)
cat_rc=$?if [ $grep_rc -eq 0 ];thenecho "$1用户存在于系统中"
elif [ $cat_rc -eq 0 ];thenecho "$1用户不存在于系统中,但有家目录"
elseecho "$1用户不存在系统中,也没有家目录"
fi[root@manage if]# sh -x var03.sh root
++ grep root /etc/passwd
+ grep_user=
+ grep_rc=0
++ ls -ld /home/root
+ cat_dir=
+ cat_rc=2
+ '[' 0 -eq 0 ']'
+ echo root用户存在于系统中
root用户存在于系统中
4.5、检查软件包是否安装
1、检查sysstat包是否安装
[root@shell]# cat soft_package.sh
#!/bin/bashif rpm -q sysstat &>/dev/nullthenecho "sysstat is already installed."elseecho "sysstat is not installed."
fi
说明: 使用if判断sysstat包有没有安装,如果安装了就打印already installed已经安装,如果没有安装就打印not installed没有安装
执行效果
[root@shell ]# sh soft_package.sh
sysstat is already installed.
2、检查mailx包是否安装
[root@shell]# cat soft_package.sh
#!/bin/bashif rpm -q mailx &>/dev/null;thenecho "mailx is already installed."
elseecho "mailx is not installed."
fi
说明: 使用if判断mailx包有没有安装,如果安装了就打印already installed已经安装,如果没有安装就打印not installed没有安装
执行效果:
[root@shell ]# sh soft_package.sh
mailx is not installed.
4.6、监控httpd服务
提示:使用netstat或ss过滤然后使用wc统计,进行判断,如果结果大于0,就表示运行,否则就发邮件报警然后启动服务
[root@shell ]# cat web.sh
#!/bin/bashif [ `netstat -untpl | grep httpd | wc -l` -gt 0 ];thenecho "httpd is Running"
elseecho "httpd service down" | mail -s "httpd" 1234567@qq.comsystemctl restart httpd
fi
4.7、监控mysql服务
[root@shell ]# cat mysql_mon.sh
#!/bin/bashif [ `netstat -untpl | grep mysqld | wc -l` -gt 0 ];thenecho "mysqld is Running"
elseecho "mysqld service down" | mail -s "mysqld" 1234567@qq.comsystemctl restart mysqld
fi
然后将写的监控脚本放进定时任务里面,多久运行一次检查。
定时任务crontab表达式参考《linux-crontab每分钟定时执行/定时任务调度》
例如:每3分钟执行一遍
*/3 * * * * root /bin/sh /scripts/web.sh &>/dev/null
*/3 * * * * root /bin/sh /scripts/mysql_mon.sh &>/dev/null
4.8、网络运算符
ping命令检测主机的可达性
ping -c 3 host :ping指定的主机,发送3个包
示例
ping -c 3 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.085 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.285 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.235 ms--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
curl命令检查网站的响应
curl -s www.baidu.com :检查服务是否响应
[@root ~]# curl -s www.baidu.com
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8>
<meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer>
<link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head>
<body link=#0000cc>
<div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper>
<div id=lg> <img hidefocus=true src=//www.baidu.com/img/
........
nc命令进行端口扫描
nc -zv www.baidu.com 80 : 检查服务端口是否开启
[@root ~]# nc -zv www.baidu.com 80
Connection to www.baidu.com port 80 [tcp/http] succeeded!
参考文章:
https://www.cnblogs.com/moox/p/12841943.html
https://blog.csdn.net/weixin_45858439/article/details/124231375
https://www.cnblogs.com/kaishirenshi/p/9729800.html