if条件语句
1、if条件语句
1.1、if条件语句的语法
1.1.1、单分支结构
第一种语法:
bash
if <条件表达式>
then
指令
fi
第二种语法:
bash
if <条件表达式>; then
指令
fi
上文的"<条件表达式>"部分可以是test、、\[]、(())等条件表达式,甚至可以直接使用命令作为条件表达式。每个if条件语句都以if开头,并带有then,最后以fi结尾。
第二种语法中的分号相当于命令换行,上面的两种语法含义是相同的,读者可根据习惯自行选择。本书中主要使用第一种语法格式。
在所有编程语言里,if条件语句几乎是最简单的语句格式,且用途最广。当if后面的<条件表达式>成立时(真),就会执行then后面的指令或语句;否则,就会忽略then后面的指令或语句,转而执行fi下面的程序。
if单分支语句执行流程逻辑图如图所示。

条件语句还可以嵌套(即if条件语句里面还有if条件语句),注意每个if条件语句中都要有一个与之对应的fi(if反过来写),每个if和它下面最近的fi成对搭配,语法示例如下:
bash
if <条件表达式>
then
if <条件表达式>
then
指令
fi
fi
提示:通常在书写Shell条件语句编程时,要让成对的条件语句关键字的缩进相对应,以便于阅读浏览。
前文曾讲解过的文件条件表达式 -f "$file1" && echo 1就等价于下面的if条件语句。
bash
if [ -f "$file1" ]; then
echo 1
fi
1.1.2、双分支结构
if条件语句的单分支结构主体就是"如果...,那么...",而if条件语句的双分支结构主体则为"如果...,那么...,否则..."。
if条件语句的双分支结构语法为:
bash
if <条件表达式>
then
指令集1
else
指令集2
fi
前文的文件测试条件表达式 -f "$file1" && echo 1 ||echo 0就相当于下面的双分支的if条件语句。
bash
if [-f "$file1" ]
then
echo 1
else
echo 0
fi
if双分支语句执行流程逻辑图如图所示。

1.1.3、多分支结构
if条件语句多分支结构的主体为"如果...,那么...,否则如果...,那么,否则如果...,那么...,否则..."。
if条件语句多分支语法为:
bash
if <条件表达式1>
then
指令1
elif <条件表达式2>
then
指令2
else
指令3
fi
-----------------------多个elif----------------------------
if <条件表达式1>
then
指令
elif <条件表达式2>
then
指令
elif <条件表达式3>
then
指令
... ...
else
指令
fi
提示:
1)注意多分支elif的写法,每个elif都要带有then。
2)最后结尾的else后面没有then。
if多分支语句执行流程对应的逻辑图如图所示。

1.2、if条件语句多种条件表达式语法
前文已经说过,if条件语句(包括双多分支if)的"<条件表达式>"部分可以是test、、\[]、(())等条件表达式,甚至还可以直接使用命令作为条件表达式,具体的语法如下。
-
(1)test条件表达式
bashif test 表达式 then 指令 fi -
(2)\[\]条件表达式
bashif [ 字符串或算术表达式 ] then 指令 fi -
(3)\[]条件表达式
bashif [[ 字符串表达式 ]] then 指令 fi -
(4)(())条件表达式
bashif ((算术表达式)) then 指令 fi -
(5)命令表达式
bashif 命令 then 指令 fi
说明:以上表达式除了语法不同之外,具体的应用是一致的,实际工作场景中,读者只需选择一种适合自己习惯的表达式就好。
1.3、单分支if条件语句实践
范例:把下面测试文件中条件表达式的语句改成if条件语句。
bash
[root@oldboy ~]# [ -f /etc/hosts ] && echo 1 #<==[](单中括号)条件表达式语法。
1
[root@oldboy ~]# [[ -f /etc/hosts ]] && echo 1 #<==[[]](双中括号)条件表达式语法。
1
[root@oldboy ~]# test -f /etc/hosts && echo 1 #<==test条件表达式语法。
1
参考答案:
bash
[root@oldboy scripts]# cat 7_1.sh
if [ -f /etc/hosts ] #<==[](单中括号)条件表达式改为if单分支语句。
then
echo "[1]"
fi
if [[ -f /etc/hosts ]] #<==[[]](双中括号)条件表达式改为if单分支语句。
then
echo "[[1]]"
fi
if test -f /etc/hosts #<==test条件表达式改为if单分支语句。
then
echo "test1"
fi
执行结果如下:
bash
[root@oldboy scripts]# sh 7_1.sh
[1]
[[1]]
test1
范例:开发Shell脚本判断系统剩余内存的大小,如果低于100MB,就邮件报警给系统管理员,并且将脚本加入系统定时任务,即每3分钟执行一次检查。
在解答示例之前,先介绍一些重要的内容:开发程序时,一定要重视分析问题及程序设计过程(例如:分模块实现第一关、第二关、第三关),确定需求并完成设计后,编码就是很容易的事情了。因此,请大家重视分析问题和程序设计的思想,而不要一上来就开始编码,这也是老男孩常说的,技术的提升仅是量的积累,思想的提升才是质的飞跃!
设计思路就是根据需求,把需求进行拆解,分模块逐步实现,例如本题可以分为如下几步:
- 1)获取当前系统剩余内存的值(先在命令行实现)。
- 2)配置邮件报警(可采用第三方邮件服务器)。
- 3)判断取到的值是否小于100MB,如果小于100MB,就报警(采用if语句)。
- 4)编码实现Shell脚本。
- 5)加入crond定时任务,每三分钟检查一次。
本例的最终实现过程如下。
-
1)获取内存大小,注意:内存大小是下面命令中对应buffers/cache那一行结尾的值(buffers)。
bash[root@oldboy scripts]# free -m total used free shared buffers cached Mem: 994 903 91 0 103 672 -/+ buffers/cache: 127 867 #<===这里的867是系统的剩余内存,因为Linux系统有缓冲和缓存的特性,即把系统多余的内存临时用于缓冲和缓存,以提升系统的性能和效率。 Swap: 0 0 0 [root@oldboy scripts]# free -m|awk 'NR==3 {print $NF}' #<===利用awk获取到867,默认单位为MB。 867 -
2)发邮件的客户端常见的有mail或mutt;服务端有sendmail服务(CentOS 5下默认的)、postfix服务(CentOS 6下默认的)。这里不使用本地的邮件服务,而是使用本地的mail客户端,以及第三方的邮件服务商,例如:163.com(需要提前注册用户),利用这个邮件账号来给接收报警的人发送报警邮件。
bash[root@oldboy scripts]# echo -e "set from=oldboy@163.com smtp=smtp.163.com\ nset smtp-auth-user=oldboy smtp-auth-password=oldboy123 smtp-auth=login" >> /etc/mail.rc #<==配置mail.rc,将Linux本地作为邮件客户端,使用注册的163账号及smtp地址发送邮件。 [root@oldboy scripts]# tail -2 /etc/mail.rc set from=oldboy@163.com smtp=smtp.163.com #<== from=oldboy@163.com为邮件地址,smtp=smtp.163.com为邮件服务器。 set smtp-auth-user=oldboy smtp-auth-password=oldboy123 smtp-auth=login #<==oldboy为用户名,oldboy123为密码。 [root@oldboy scripts]# echo "oldboy"|mail -s "title" oldboy@163.com #<==测试邮件发送(服务器要能上网)。 [root@oldboy scripts]# echo oldboy >/tmp/test.txt #<==将正文放入文件。 [root@oldboy scripts]# mail -s "title" oldboy@163.com </tmp/test.txt #<==读取文件内容并发送邮件。查看163邮件是否发送成功,本书是用自己的账号给自己发送邮件。 -
3)编写Shell脚本。
bash
[root@oldboy scripts]# cat 7_2.sh
FreeMem=`free -m|awk 'NR==3 {print $NF}'` #<==获取系统当前的内存值,赋给变量FreeMem。
CHARS="Current memory is $FreeMem." #<==定义字符串CHARS变量,作为输出及供邮件正文使用。
if [ $FreeMem -lt 100 ] #<==[](单中括号)条件表达式语法,这是老男孩推荐的用法,如果小于100,则执行命令。
then
echo $CHARS|tee /tmp/messages.txt #<==屏幕输出提示,并写入文件。
mail -s "`date +%F-%T`$CHARS" test@oldboyedu.com </tmp/messages.txt
#<==发送邮件报警。
fi
提示:test@oldboyedu.com是报警邮箱,工作中应尽量使用企业邮箱,以防止邮件被屏蔽。
执行测试:
bash
[root@oldboy scripts]# /bin/sh /server/scripts/7_2.sh
Current memory is 866.
提示:
- 1) 测试时,我们没办法把内存调小,但可以把阈值调大,例如将100MB改成1000MB。
- 2)注意,如果使用第三方邮件服务,则服务器本地无需开启邮件服务。
接下来,把上述脚本加入crond定时任务中,每3分钟检查一次,达到阀值就发邮件报警:
bash
[root@oldboy scripts]# crontab -l|tail -2
# monitor sys mem at 20160813 by oldboy
*/3 * * * * /bin/sh /server/scripts/7_2.sh &>/dev/null
监测内存并报警有多种Shell写法,如下:
bash
if (($FreeMem<1000)) #<==(())条件表达式语法。
then
echo $CHARS|tee /tmp/messages.txt
#mail -s "`date +%F-%T`$CHARS" 490004487@qq.com </tmp/messages.txt
fi
if [[ $FreeMem -lt 1000 ]] #<==[[]]条件表达式语法。
then
echo $CHARS|tee /tmp/messages.txt
#mail -s "`date +%F-%T`$CHARS" 490004487@qq.com </tmp/messages.txt
fi
if test $FreeMem -lt 1000 #<==test条件表达式语法。
then
echo $CHARS|tee /tmp/messages.txt
#mail -s "`date +%F-%T`$CHARS" 490004487@qq.com </tmp/messages.txt
fi
1.4、if条件语句的深入实践
范例:分别使用read读入及脚本传参的方式比较两个整数的大小。
参考答案1:使用单分支if语句和read读入实现整数大小的比较。
比较两个整数的大小有三种情况,因此用一个单分支if是无法实现的,需要3个单分支的if判断才行,每一个单分支if条件语句相当于前文的一个条件表达式判断,最终的脚本如下:
bash
[root@oldboy scripts]# cat 7_3_1.sh
#! /bin/sh
read -p "pls input two num:" a b #<==读入两个输入,分别赋值给变量a和b。
if [ $a -lt $b ]; then #<==如果$a小于$b,则执行命令。
echo "yes, $a less than $b" #<==打印输出,提醒用户。
exit 0 #<==判断完毕,成功执行,以0值退出脚本,此处如果不退出,则会继续执行下面的if语句,而这是不必要的。
fi
if [ $a -eq $b ]; then #<==如果$a等于$b,则执行命令,同理,成功后以0值退出脚本。
echo "yes, $a equal $b"
exit 0
fi
if [ $a -gt $b ]; then #<==如果$a大于$b,则执行命令,同理,成功后以0值退出脚本。
echo "yes, $a greater than $b"
exit 0
fi
本例执行结果如下:
bash
[root@oldboy scripts]# sh 7_3_1.sh
pls input two num:6 2
yes,6 greater than 2
[root@oldboy scripts]# sh 7_3_1.sh
pls input two num:2 6
yes,2 less than 6
[root@oldboy scripts]# sh 7_3_1.sh
pls input two num:6 6
yes,6 equal 6
提示:此题目并未要求对传参个数及参数是否为整数进行判断,读者可以自己试一试,如果有问题,可以参考前文及后文的讲解。
上述使用if单分支语句比较参数大小的脚本有几个问题:
- 没有对参数的个数及传入变量是不是整数做判断。
- if条件语句多而杂,导致逻辑不够清晰。
那么有没有好一点的方法呢?当然有,见后文多分支if及case语句功能。
参考答案2:使用多分支if语句和利用read读入变量实现整数大小的比较。
bash
[root@oldboy scripts]# cat 7_3_2.sh
#! /bin/sh
read -p "pls input two num:" a b #<==读入两个输入,分别赋值给变量a和b。
if [ $a -lt $b ]; then #<==使用if多分支语法进行比较。
echo "yes, $a less than $b" #<==由于是一个if语句,因此就不需要退出脚本了。
elif [ $a -eq $b ]; then
echo "yes, $a equal $b"
else [ $a -gt $b ]
echo "yes, $a greater than $b"
fi
执行结果如下:
bash
[root@oldboy scripts]# sh 7_3_2.sh
pls input two num:8 4
yes,8 greater than 4
[root@oldboy scripts]# sh 7_3_2.sh
pls input two num:4 8
yes,4 less than 8
[root@oldboy scripts]# sh 7_3_2.sh
pls input two num:8 8
yes,8 equal 8
参考答案3:用脚本传参的方式比较整数大小。
对上文的read脚本进行简单修改即可实现传参的比较。单分支实现脚本如下:
bash
[root@oldboy scripts]# cat 7_3_3.sh
#! /bin/sh
a=$1 #<==将脚本命令行的第一个参数赋值给变量a。
b=$2 #<==将脚本命令行的第二个参数赋值给变量b。
if [ $a -lt $b ]; then
echo "yes, $a less than $b"
exit 0
fi
if [ $a -eq $b ]; then
echo "yes, $a equal $b"
exit 0
fi
if [ $a -gt $b ]; then
echo "yes, $a greater than $b"
exit 0
fi
多分支实现脚本如下:
bash
[root@oldboy scripts]# cat 7_3_4.sh
#! /bin/sh
a=$1 #<==将脚本命令行的第一个参数赋值给变量a。
b=$2 #<==将脚本命令行的第二个参数赋值给变量b。
if [ $a -lt $b ]; then
echo "yes, $a less than $b"
elif [ $a -eq $b ]; then
echo "yes, $a equal $b"
else [ $a -gt $b ]
echo "yes, $a greater than $b"
fi
2、if条件语句企业案例精讲
2.1、监控Web和数据库的企业案例
范例:用if条件语句针对Nginx Web服务或MySQL数据库服务是否正常进行检测,如果服务未启动,则启动相应的服务。
这是企业级运维实战综合题,需要读者对Nginx Web服务或MySQL数据库服务很熟悉才行,本例同样适用于其他的Web服务和数据库服务。
大家还记得前面说过的开发程序前的三部曲吧?这里就采用这种方式来解答此题。
(1)分析问题
先想一想监控Web服务和MySQL数据库服务是否异常的方法有哪些,见表。

此外,对端口进程等进行判断时,尽量先通过grep过滤端口和进程特殊标记字符串,然后结合wc将过滤到的结果转成行数再比较,这样相对简单有效,且经过wc -l命令处理之后的结果一定是数字,这样再进行判断就会比较简便。如果单纯地根据具体的列取具体的值判断会很麻烦,如果确实想采用取值判断的方法,那就尽量用字符串比较的语法。
(2)监测MySQL数据库异常
- 1)MySQL数据库环境准备,如下:
bash
[root@oldboy ~]# yum install mysql-server -y
[root@oldboy ~]# /etc/init.d/mysqld start
正在启动 mysqld: [确定]
[root@oldboy ~]# netstat -lntup|grep mysql
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 2275/mysqld
-
2)通过命令行检测数据库服务是否正常,只有先确定命令行是正确的,才能确保将它放到脚本里也是正确的。
首先采用端口监控的方式。在服务器本地监控端口的命令有netstat、ss、lsof,具体实现多种命令的方法如下:
bash[root@oldboy scripts]# netstat -lnt|grep 3306|awk -F "[ :]+" '{print $5}' #<==这个就是前面所描述的根据具体的列取值判断的方法,获取到值,然后看看其是否等于3306,老男孩不推荐采用这种取值方法,因为第一取值麻烦;第二如果使用数字比较,当端口不存在时就会报错,而一旦使用了取值判断方法, 即使看起来是数字,也要尽量使用字符串进行比较,否则你将掉进坑里,很久都不会爬出来。 3306 [root@oldboy scripts]# netstat -lntup|grep 3306|wc -l #<==过滤关键字端口,转成数字,此方法很好。 1 [root@oldboy scripts]# netstat -lntup|grep mysql|wc -l #<==过滤关键字进程,转成数字,此方法很好。 1 [root@oldboy scripts]# ss -lntup|grep mysql|wc -l #<==ss类似于netstat命令,参数选项可通用。 1 [root@oldboy scripts]# ss -lntup|grep 3306|wc -l #<==ss类似于netstat命令,参数选项可通用。 1 [root@oldboy scripts]# lsof -i tcp:3306|wc -l #<==利用lsof检查tcp协议的3306端口。 2从远端监控服务器监控本地端口的命令有telnet、nmap、nc,这三个命令有可能需要事先安装好才能使用,安装方法为:
bash[root@oldboy scripts]# yum install telnet nmap nc -y [root@oldboy scripts]# nmap 127.0.0.1 -p 3306|grep open|wc -l #<==查看远端3306端口是否开通,过滤open关键字,结果返回1,说明有open关键字,表示3306端口是通的。 1 [root@oldboy scripts]# echo -e "\n"|telnet 127.0.0.1 3306 2>/dev/null|grep Connected|wc -l #<==telnet是常用来检测远端服务器端口是否通畅的一个好用的命令,在非交互时需要采用特殊写法才行,过滤的关键字为Connected,返回1,说明有Connected,表示3306端口是通的。 1 [root@oldboy scripts]# nc -w 2 127.0.0.1 3306 &>/dev/null #<==nc的命令很强大,这里用来检测端口。根据执行命令的返回值判断端口是否通畅,如果返回0,则表示通畅,-w为超时时间。 [root@oldboy scripts]# echo $? 0本例为了统一IP地址,因此使用的都是同一个IP,即127.0.0.1,在实际工作中,应该用自己服务器的IP来替代。
下面对服务进程或进程数进行监控(适合本地服务器):
bash[root@oldboy scripts]# ps -ef|grep mysql|grep -v grep|wc -l 3以下是在客户端模拟用户访问的方式进行监控。
使用wget或curl命令访问URL地址来测试(如果要检测数据库是否异常,需要转为通过访问Web服务器去访问数据库)时,有三种判断思路。
第一种是根据执行命令的返回值判断成功与否,本例的URL使用了网上的地址,在实际工作中应使用开发人员提供给我们的访问数据库的程序地址。
bash[root@oldboy scripts]# wget --spider --timeout=10 --tries=2 www.baidu.com &>/dev/null #<==在wget后面加url的检测方法,&>/dev/null表示不输出,只看返回值。--spider的意思是模拟爬取,--timeout=10的意思是10秒超时,--tries=2表示如果不成功,则重试2次。 [root@oldboy scripts]# echo $? #<==查看命令执行的返回值,0为成功。 0 [root@oldboy scripts]# wget -T 10 -q --spider http://www.baidu.com >&/dev/ null #<==用法同第一个wget, -q表示安静的。 [root@oldboy scripts]# echo $? #<==查看命令执行的返回值,0为成功。 0 [root@oldboy scripts]# curl -s -o /dev/null http://www.baidu.com #<==利用curl进行检测,-s为沉默模式,-o /dev/null表示将输出定向到空。 [root@oldboy scripts]# echo $? #<==查看命令执行的返回值,0为成功。 0第二种是根据执行命令后获取到的字符串进行判断。此方法需要有前端动态程序支持,即开发PHP或Java程序从数据库里取出指定的字符串,看它和期待的是否相等。下面以PHP服务为例(对于一个PHP程序访问数据库,如果访问成功,则给出固定的输出)。
bash[root@oldboy scripts]# /server/scripts/testmysql.php <? php /* #this scripts is created by oldboy #oldboy QQ:31333741 #site: http://www.etiantian.org #blog: http://oldboy.blog.51cto.com */ //$link_id=mysql_connect('主机名', '用户', '密码'); $link_id=mysql_connect('localhost', 'root', 'matianhai') or mysql_error(); //$link_id=mysql_connect('localhost', 'test', ''); if($link_id){ echo "mysql successful by oldboy ! "; }else{ echo mysql_error(); } ?>命令行执行:
bash[root@oldboy scripts]# php /server/scripts/testmysql.php #<==注意.php需执行 (yuminstall php -y)安装 mysql successful by oldboy ! #<==可以通过grep过滤这里输出的关键字,进而判断访问数据库是否成功。
提示:需要事先安装PHP软件才行,或者将程序放到Lnmp服务器的站点目录,然后curl或\wget访问http地址。此方法是监控数据库是否异常的最佳的方法。
3)开发监控MySQL数据库的脚本。
脚本1:
bash
#! /bin/sh
echo method1-------------------
if [ `netstat -lnt|grep 3306|awk -F "[ :]+" '{print $5}'` -eq 3306 ]
#<==这里的判断思路不是很好,即①最好不要用整数进行比较,因为一旦端口不存在,取值就会为空,进行整数比较会报错。②不要根据列取具体的值,而是要过滤关键字,通过wc转成行数判断。
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi
脚本2:
bash
echo method2-------------------
if [ "`netstat -lnt|grep 3306|awk -F "[ :]+" '{print $5}'`" = "3306" ]
#<==用字符串的方式进行比较就好多了,避免了脚本1中整数比较的错误发生,但是取值麻烦了一些。
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi
脚本3:
bash
echo method3-------------------
if [ `netstat -lntup|grep mysqld|wc -l` -gt 0 ] #<==过滤进程名,转成数字,很优秀的取值判断方法。
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi
脚本4:
bash
echo method4-------------------
if [ `lsof -i tcp:3306|wc -l` -gt 0 ] #<==过滤端口转成数字,很优秀的取值判断方法。
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi
脚本5:
bash
echo method5-------------------
[ `rpm -qa nmap|wc -l` -lt 1 ] && yum install nmap -y &>/dev/null
#<==防止因nmap没有安装而导致的错误。
if [ `nmap 127.0.0.1 -p 3306 2>/dev/null|grep open|wc -l` -gt 0 ]
#<==远端的端口检查,推荐使用,同理,这里也不要过滤出open,然后再做字符比较,转成数字最佳。
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi
脚本6:
bash
echo method6-------------------
[ `rpm -qa nc|wc -l` -lt 1 ] && yum install nc -y &>/dev/null
#<==防止因nc没有安装而导致的错误。
if [ `nc -w 2 127.0.0.1 3306 &>/dev/null&&echo ok|grep ok|wc -l` -gt 0 ]
#<==这个判断有点特别,即若nc执行成功,则输出和之后的过滤都没问题,最后转成数字,思路决定出路。
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi
脚本7:
bash
echo method7-------------------
if [ `ps -ef|grep -v grep|grep mysql|wc -l` -gt 0 ] #<==传统的过滤进程的方法,grep
-v grep是排除此命令自身。
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi
(3)监控Nginx Web服务异常
监控Nginx Web服务异常的方法和监控MySQL数据库一样,也是使用端口、进程或通过wget/curl访问来进行检测。
-
1)Nginx web服务环境准备,如下:
bash[root@oldboy ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun. com/repo/epel-6.repo [root@oldboy ~]# yum install nginx -y [root@oldboy ~]# /etc/init.d/nginx start 正在启动 Nginx: [确定] [root@oldboy scripts]# echo oldboy >/usr/share/nginx/html/index.html #<==建立测试网页,内容为oldboy。 [root@oldboy scripts]# curl http://127.0.0.1 #<==返回oldboy。 oldboy -
2)通过命令行检测Nginx服务是否正常,同样只有命令行是正确的,才能确保它放到脚本里也是正确的。
首先采用端口监控的方式。在监控Nginx和监控数据库端口时,除了端口不同,其他的命令方法都是一模一样的,想要了解详细注释,可参见前文监控数据库的代码注释。在服务器本地监控端口的命令有netstat、ss、lsof,如下:
bash[root@oldboy ~]# netstat -lnt|grep -w 80|awk -F "[ :]+" '{print $5}' 80 [root@oldboy ~]# netstat -lntup|grep -w 80|wc -l 1 [root@oldboy ~]# netstat -lntup|grep mysql|wc -l 1 [root@oldboy ~]# ss -lntup|grep mysql|wc -l 1 [root@oldboy ~]# ss -lntup|grep -w 80|wc -l 1 [root@oldboy ~]# lsof -i tcp:80|wc -l 3在远端监控服务器本地端口的命令有telnet、nmap、nc,如下:
bash[root@oldboy ~]# nmap 127.0.0.1 -p 80|grep open|wc -l 1 [root@oldboy ~]# echo -e "\n"|telnet 127.0.0.1 80 2>/dev/null|grep Connected|wc -l 1 [root@oldboy ~]# nc -w 2 127.0.0.1 80 &>/dev/null [root@oldboy ~]# echo $? 0对服务进程或进程数进行监控的方式(适合本地服务器)如下:
bash[root@oldboy ~]# ps -ef|grep nginx|grep -v grep|wc -l 2 [root@oldboy ~]# ps -C nginx --no-header 3147 ? 00:00:00 nginx 3150 ? 00:00:00 nginx [root@oldboy ~]# ps -C nginx --no-header|wc -l 2以下是在客户端模拟用户访问的监控方式。先通过wget或curl命令进行测试。执行wget或curl命令之后,再看返回值($? ),为0,则成功。
bash[root@oldboy ~]# wget --spider --timeout=10 --tries=2 http://127.0.0.1 &>/ dev/null [root@oldboy ~]# echo $? 0 [root@oldboy ~]# wget -T 10 -q --spider http://127.0.0.1 &>/dev/null [root@oldboy ~]# echo $? 0 [root@oldboy ~]# curl -s -o /dev/null http://127.0.0.1 [root@oldboy ~]# echo $? 0以下是获取字符串的方式(判断获取的字符串是否和事先设定的相等)。
bash[root@oldboy ~]# curl http://127.0.0.1 #<==根据指定的返回值判断服务是否正常。 oldboy以下是根据HTTP响应header的结果进行判断(200、301、302都表示正常)。
bash[root@oldboy ~]# curl -I -s -w "%{http_code}\n" -o /dev/null http://127.0.0.1 200
脚本1:
bash
[root@oldboy scripts]# cat 7_5.sh
#! /bin/sh
echo http method1-------------------
if [ `netstat -lnt|grep 80|awk -F "[ :]+" '{print $5}'` -eq 80 ]
#<==取端口数字表 ,有Bug,不建议使用,如果非要取端口,则请改为字符串比较的语法。
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
脚本2:
bash
echo http method2-------------------
if [ "`netstat -lnt|grep 80|awk -F "[ :]+" '{print $5}'`" = "80" ]
#<==字符串比较语法,取值太麻烦,不如过滤后转为行数再比较的方法好。
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
脚本3:
bash
echo http method3-------------------
if [ `netstat -lntup|grep nginx|wc -l` -gt 0 ]
#<==通过检查端口的命令,过滤进程名(比过滤端口好)转成数字后再比较,这是推荐的用法。
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
脚本4:
bash
echo http method4-------------------
if [ `lsof -i tcp:80|wc -l` -gt 0 ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
脚本5:
bash
echo http method5-------------------
[ `rpm -qa nmap|wc -l` -lt 1 ] && yum install nmap -y &>/dev/null
if [ `nmap 127.0.0.1 -p 80 2>/dev/null|grep open|wc -l` -gt 0 ]
#<==nmap检测方法,优势是适合从远端进行检查,推荐使用。
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
脚本6:
bash
echo http method6-------------------
[ `rpm -qa nc|wc -l` -lt 1 ] && yum install nc -y &>/dev/null
if [ `nc -w 2 127.0.0.1 80 &>/dev/null&&echo ok|grep ok|wc -l` -gt 0 ]
#<==nc方法,前面已讲解过。
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
脚本7:
bash
echo http method7-------------------
if [ `ps -ef|grep -v grep|grep nginx|wc -l` -ge 1 ] #<==过滤进程方式,排除自身。
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
脚本8:
bash
echo http method8-------------------
if [[ `curl -I -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1` =~
[23]0[012] ]]
#<== 获取状态码,然后做正则数字匹配(目标是200、301、302,但实际上多余了几个201、202、
300),这是[[]]的特殊匹配用法之一,前文也讲过了。
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
脚本9:
bash
echo http method9-------------------
if [ `curl -I http://127.0.0.1 2>/dev/null|head -1|egrep "200|302|301"|wc
-l` -eq 1 ]
#<==此方法通过扩展的egrep过滤正确的状态码,然后利用wc转成数字,此方法比较优秀,推荐读者使用。
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
脚本10:
bash
echo http method10-------------------
if [ "`curl -s http://127.0.0.1`" = "oldboy" ]
#<== 根据访问网站URL,将返回的结果和期待的值进行比较,这个方法略微麻烦,但是结果最准确,
适用于数据库及更深层次的对网站集群后端各个应用的检测。
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
2.2、比较大小的经典拓展案例
范例:使用if条件语句比较两个整数的大小。使用传参方法时,需要对传参个数及传入的参数是否为整数进行判断。
参考答案:
bash
[root@oldboy scripts]# cat 7_5_1.sh
#! /bin/bash
a=$1 #<==将脚本命令行的第一个参数赋值给变量a。
b=$2 #<==将脚本命令行的第二个参数赋值给变量b。
#no.1 judge arg nums.
if [ $# -ne 2 ]; then #<==判断传参个数。
echo "USAGE:$0 arg1 arg2" #<==若传参个数不符合要求,则打印提示后退出脚本。
exit 2
fi
#no.2 judge if int
expr $a + 1 &>/dev/null #<==判断变量a是否为整数。
RETVAL1=$? #<==获取expr命令的返回值并赋值给RETVAL1。
expr $b + 1 &>/dev/null #<==判断变量b是否为整数。
RETVAL2=$? #<==获取expr命令的返回值并赋值给RETVAL2。
if [ $RETVAL1 -ne 0 -a $RETVAL2 -ne 0 ]; then
#<==执行判断,如果返回值不都为0,说明至少有一个变量不是整数,则打印提示,退出脚本。
echo "please input two int again"
exit 3
fi
#no.3 compart two num.
#<==经过参数个数判断及整数判断后,就可以放心地进行比较了。
if [ $a -lt $b ]; then
echo "$a<$b"
elif [ $a -eq $b ]; then
echo "$a=$b"
else
echo "$a>$b"
fi
对于新手,老男孩不推荐使用if条件语句的复杂判断写法(逻辑不够清晰)。
bash
#! /bin/sh
read -p "Pls input two num:" a b
#no2 udge a and b if is int
expr $a + 0 &>/dev/null
RETVAL1=$?
expr $b + 0 &>/dev/null
RETVAL2=$?
if [ -z "$a" ] || [ -z "$b" ]
then
echo "Pls input two num agagin."
exit 1
elif test $RETVAL1 -ne 0 -o $RETVAL2 -ne 0
then
echo "Pls input two "num" again."
exit 2
elif [ $a -lt $b ]
then
echo "$a < $b"
elif [ $a -eq $b ]
then
echo "$a = $b"
else
echo "$a > $b"
fi
exit 0
2.3、判断字符串是否为数字的多种思路
范例7-6:判断字符串是否为数字的多种思路。
参考答案1:使用sed加正则表达式。
判断思路:删除一个字符串中的所有数字,看字符串的长度是否为0,如果不为0,则说明不是整数。
bash
[root@oldboy scripts]# [ -n "`echo oldboy123|sed 's/[0-9]//g'`" ] && echo
char || echo int
char
[root@oldboy scripts]# [ -n "`echo 123|sed 's/[0-9]//g'`" ] && echo char ||
echo int
int
[root@oldboy scripts]# [ -z "`echo 123|sed 's/[0-9]//g'`" ] && echo int ||
echo char
int
[root@oldboy scripts]# [ -z "`echo oldgirl123|sed 's/[0-9]//g'`" ] && echo
int || echo char
char
除了使用sed的替换外,还可以使用变量的子串替换等方法,如下:
bash
[root@oldboy scripts]# num=oldboy521
[root@oldboy scripts]# [ -z "`echo "${num//[0-9]/}"`" ] && echo int || echo char
char
[root@oldboy scripts]# num=521
[root@oldboy scripts]# [ -z "`echo "${num//[0-9]/}"`" ] && echo int || echo char
int
参考答案2:变量的子串替换加正则表达式(特殊判断思路)。
判断思路:如果num的长度不为0,并且把num中的非数字部分删除,然后再看结果是不是等于num本身,如果两者都成立,则num就是数字。
bash
-n "$num" #<==如果num长度不为0,则表达式成立。
"$num" = "${num//[^0-9]/}" #<==把num中的非数字部分删除(即把字母删除),然后看结果是不是等于num本身,如果两者都成立,就是数字。
#例:对于非数字oldboy123,删除oldboy,就是123了,肯定不等于oldboy123。
#例:如果是数字123,删除非数字的部分,结果还是123,肯定等于123。
完整表达式如下:
bash
[root@oldboy scripts]# num=521
[root@oldboy scripts]# [ -n "$num" -a "$num" = "${num//[^0-9]/}" ] && echo
"it is num"
it is num
[root@oldboy scripts]# num=oldboy521
[root@oldboy scripts]# [ -n "$num" -a "$num" = "${num//[^0-9]/}" ] && echo
"it is num"
参考答案3:通过expr计算判断(前文已用过多次了)。
bash
[root@oldboy scripts]# expr oldboy + 1 &>/dev/null #<==把字符串或变量和整数相加看执行是否成功。
[root@oldboy scripts]# echo $?
2
[root@oldboy scripts]# expr 123 + 1 &>/dev/null
[root@oldboy scripts]# echo $?
0
[root@oldboy scripts]# expr 0 + 0 &>/dev/null
[root@oldboy scripts]# echo $?
1
参考答案4:利用"=~"符号判断
bash
[root@oldboy scripts]# [[ oldboy123 =~ ^[0-9]+$ ]] && echo int || echo char
char
[root@oldboy scripts]# [[ 123 =~ ^[0-9]+$ ]] && echo int || echo char
int
参考答案5:利用bc判断字符串是否为整数(仅为参考方法,不推荐,因为有Bug)。
bash
[root@oldboy scripts]# echo oldboy|bc
0
[root@oldboy scripts]# echo oldboy123|bc
0
[root@oldboy scripts]# echo 123|bc #<==返回结果为本身的就是整数。
123
[root@oldboy scripts]# echo 123oldboy|bc
(standard_in) 1: syntax error
2.4、判断字符串长度是否为0的多种思路
范例:实现判断字符串长度是不是为0的多种方法。
1)使用字符串条件表达式-z和-n的语法如下:
bash
[root@oldboy scripts]# [ -z "oldboy" ] && echo 1 || echo 0
0
[root@oldboy scripts]# [ -n "oldboy" ] && echo 1 || echo 0
1
2)使用变量子串判断的语法如下:
bash
[root@oldboy scripts]# char=oldboy
[root@oldboy scripts]# [ ${#char} -eq 0 ] && echo 1 || echo 0
3)使用expr length函数判断的语法如下:
bash
[root@oldboy scripts]# [ `expr length "oldboy"` -eq 0 ] && echo 1 || echo 0
0
4)使用wc的-L参数统计判断的语法如下:
bash
[root@oldboy scripts]# [ ` echo oldboy|wc -L ` -eq 0 ] && echo 1 || echo 0
0
5)使用awk length函数判断的语法如下:
bash
[root@oldboy scripts]# [ `echo oldboy|awk '{print length}'` -eq 0 ] &&
echo 1 || echo 0
0