shell 编程 01 -- 常用操作符 及 if 条件句介绍与应用

shell 编程 01 -- 常用操作符 及 if 条件句介绍与应用

1.常用操作符

文件测试操作符

文件操作符 全称 说明
-f 文件 file 文件存在且为普通文件则真
-d 文件 directory 文件存在且为目录文件则真
-s 文件 size 文件存在且文件大小不为0则真
-e 文件 exist 文件存在则真,区别于-f
-r 文件 read 文件存在且可读则真
-w 文件 write 文件存在且可写则真
-x 文件 executable 文件存在且可执行则真
-L 文件 link 文件存在且为连接文件则真
f1 -nt f2 newer than 文件f1比文件f2新则真
f1 -ot f2 older than 文件f1比文件f2旧则真
更多... more man test

字符串测试操作符

操作符 理解 说明
-z "字符串" ! -z = -n zero 若串长度为0则真,-z可以理解为zero
[ -z "abd" ]&& echo 1 || echo 0
-n "字符串" no zero 若串长度不为0则为真,-n可以理解为no zero
[ -n "abd" ]&& echo 1 || echo 0
=[ ! -z "abd" ]&& echo 1 || echo 0
"串1" = "串2" equal 若串1等于串2则为真,==或=均可
test=zhangfd
[ "$test" = "zhangfd" ]&& echo 1 || echo 0
"串1" != "串2" not equal 若串1不等于串2则为真,!==或!=均可
注意:符号两端必须有空格 以上四条可以man test查看

整数二元比较操作符

比较符,在[] 中使用 比较符,在(())或[[]] 中使用,双重括号 说明
-eq = 或 == equal的缩写,相等
-ne != not equal的缩写,不相等
-gt > greater than,大于
-ge ">=" greater ,equal,大于等于
-lt < less than,小于
-le "<=" less,equal,小于等于

提示:工作中尽量不要使用双重括号,双重括号是按位比较

shell 编程 01 -- 常用操作符 及 if 条件句介绍与应用

逻辑操作符

在[]和test中使用的逻辑操作符 在[[]]中使用的逻辑操作符 说明
-a && and,与,两端都为真,则真
-o || or,或,两端有一个真则真
not,非,相反则为真

实例1:数值比较大小

数值比较大小,不同方法实现

shell 编程 01 -- 常用操作符 及 if 条件句介绍与应用

解答1:脚本传参实现

## 将非数值替换为空,再次将替换为空后的值 与 原值作比较,作为输入非数值的判断
echo "123abc" |sed -r ‘s#[^0-9]##g‘    ## 将非数值替换为空
[ `echo "123abc" |sed -r ‘s#[^0-9]##g‘` = "123abc" ] && echo 1|| echo 0

#!/bin/bash

## no.1 -- check num of args
[ $# -ne 2 ] && {
    echo "USAGE: sh c1.sh num1 num2"
    exit 1
}
## no.2 -- check int of first arg
[ `echo "$1" | sed -r ‘s/[^0-9]//g‘` = "$1" ] ||{
    echo "$1 is not int.please input a intger."
    exit 2
}
## -- check int of second arg 
[ `echo "$2"|sed -r ‘s/[^0-9]//g‘` = "$2" ] ||{
    echo "$2 is not int.please input a intger."
    exit 2
}
## no.3 compare
[ $1 -eq $2 ] && {
    echo "$1 = $2"
    exit 0
}
[ $1 -lt $2 ] && {
    echo "$1 < $2"
    exit 0
}
[ $1 -gt $2 ] && {
    echo "$1 > $2"
    exit 0
}

解答2:read实现

#!/bin/bash

read -p "pls input two nums:" num1 num2
a=$num1
b=$num2

## no.1 -- check num of args
[ -z "$a" -o -z "$b" ] && {
    echo "USAGE: sh "$0" num1 num2"
    exit 1
}
## no.2 -- check int of first arg
[ "`echo "$a" | sed -r ‘s/[^0-9]//g‘`" = "$a" ] ||{
    echo "first arg must be int,please input a intger."
    exit 2
}
## -- check int of second arg 
[ "`echo "$b"|sed -r ‘s/[^0-9]//g‘`" = "$b" ] ||{
    echo "second arg must be int,please input a intger."
    exit 3
}
## no.3 compare
[ "$a" -eq "$b" ] && {
    echo "$a = $b"
    exit 0
}
[ "$a" -lt "$b" ] && {
    echo "$a < $b"
    exit 0
}
[ "$a" -gt "$b" ] && {
    echo "$a > $b"
    exit 0
}
解答三:将read解答方法中的read去掉,将$num1 和$num2换为数字即可

实例2:打印选择菜单

打印选择菜单,一键安装web服务

shell 编程 01 -- 常用操作符 及 if 条件句介绍与应用

  • 参考答案:大战前的热身准备

    [root@zabbix scripts]# cat menu1.sh 
    #!/bin/bash
    
    cat <<zfd
        echo "1.esther"
        echo "2.xiaobaobao"
    zfd
    read -p "which one would you like?  " a
    echo "I guess you like is ${a}.  haha"
    
    

答案:函数打印

[root@zabbix scripts]# cat menu.sh 
#!/bin/bash

menu(){
cat <<zfd
    1.[install lamp]
    2.[install lnmp]
    3.[exit]
    pls input the num you want:
zfd
}
menu
read num
[ "$num" = "1" ] &&{
    echo "start installing lamp."
    [ -x /server/scripts/lamp.sh ] ||{
        echo lamp.sh can not be exec.
        exit 2
    }
    /server/scripts/lamp.sh
    echo "lamp is installed."
    exit 0
}
[ "$num" = "2" ] &&{
    echo "start installing lnmp."
    [ -x /server/scripts/lnmp.sh ] || {
        echo "lnmp.sh can not be exec."
        exit 2
    }
    /server/scripts/lnmp.sh
    echo "lnmp is installed."
    exit 0
}
[ "$num" = "3" ] && {
    echo "bye."
    exit 0
}
echo "input Error."
exit 1

2.分支与循环结构

if -- 单分支结构

  • if 条件句单分支结构语法:
if [ 条件 ]
	then 
		指令
fi
# 或
if [ 条件 ];then
	指令
fi
## 等价情况
[ -f "$file" ] && echo 1 ## 等价于
if [ -f "$file" ]; then 
	echo 1
fi

if-else -- 双分支结构

  • if 条件句双分支结构语法:
if [ 条件 ]
	then 
		指令集1
else 
	指令集2
fi
# 等价于
[ -f "$file" ] && echo 1 || echo 0
## 放在一行时的写法,加分号 ;
if [ -f "$file" ] ;then echo 1;else echo 0;fi

if - elif - else -- 多分支结构

  • if 条件句多分支结构语法:
if [ 条件 ]
	then 
		指令1
elif 条件2
	then
		指令2
else
	指令3
fi
## elif可有多个
elif 条件3
	then
		指令3
...

if单分支实例1:内存大小检查

? 开发shell脚本判断系统剩余内存的大小,如果低于100M 就邮件报给管理员,并且加入系统定时任务,每三分钟执行一次检查。

分析:

  • 1.如何取内存,内存取哪个值?(buff/cache)
## free -m 结果为4行的取法
free -m |awk ‘NR==3 {print $NF}‘
free -m |grep "buffers/" |awk ‘{print $NF}‘
free -m |grep buffers\/ |awk ‘{print $NF}‘
free -m|awk ‘/buffers/ {print $NF}‘  -- 匹配buffers所在行,取出最后一列
## free -m 结果为3行的取法
[root@zabbix scripts]# free -m
              total        used        free      shared  buff/cache   available
Mem:            974         104         732           7         137         715
Swap:          2047           0        2047
[root@zabbix scripts]# free -m|awk ‘NR==2 {print $6}‘
137
  • 2.发邮件,CenOS6及以上版本默认postfix服务要开启
echo -e "set from=zhangfd2020@163.com smtp=smtp.163.com\nset smtp-auth-user=zhangfd2020@163.com smtp-auth-password=用户授权密码 smtp-auth=login" >> /etc/mail.rc
tail -2 /etc/mail.rc
systemctl start postfix
echo "postfix function exp" > /tmp/moox.txt
mail -s "title content" 2144865225@qq.com < /tmp/moox.txt
echo "postfix function exp"|mail -s "title content" 2144865225@qq.com

## 脚本函数
#### config mail service ####
function postfix(){
	echo -e "set from=zhangfd2020@163.com smtp=smtp.163.com\nset smtp-auth-user=zhangfd2020@163.com smtp-auth-password=用户授权密码 smtp-auth=login" >> /etc/mail.rc

	systemctl start postfix
}
postfix
  • 3.编写脚本(以centos7为例)
cat judge_system_mem.sh
#!/bin/bash

cur_free=`free -m|awk ‘/Mem/ {print $6}‘`
chars="current memory is $cur_free ."
if [ $cur_free -lt 100 ]
	then 
		echo $chars |mail -s "$chars" 2144865225@qq.com
fi
  • 4.将脚本加入定时任务,每分钟检查,达到阈值就报警
echo -e "# monitor free -m \n*/3 * * * * /bin/sh /server/scripts/judge_system_mem.sh >/dev/null 2>&1">> /var/spool/cron/root
  • 扩展
取磁盘空间,df -h -- avail
取MySQL,lsof -i:3306 或 netstat -lntup|grep mysqld|wc -l

if双分支实例2:判断服务是否正常

  • 用if 双分支实现对nginx或MySQL服务是否正常进行判断,使用进程数、端口、URL的方式判断,如果进程没起,则启动进程。

  • 扩展了解:

    1. 监控web服务是否正常,不低于5中思路
    2. 监控db服务是否正常,不低于5中思路

方法:

  1. 端口
    本地:netstat 、ss、lsof
    远程:telnet、nmap、nc
    telnet-nc-nmap:查看远端的端口是否通畅3个简单实用案例!

  2. 进程(本地):ps -ef|grep [n]ginx|wc -l

  3. wget、curl(http方式,判断根据返回值或返回内容)

  4. header(http),(http方式,根据状态码判断)

  5. 数据库特有:通过MySQL客户端连接,根据返回值或返回内容判断

检查MySQL进程

cat check.db.sh
#!/bin/bash
# local
# if [ `ps -ef|grep [m]ysqld |wc -l ` -gt 0 ] 
# if [ `netstat -lntup|grep [m]ysqld |wc -l ` -gt 0 ] 
# if [ `lsof -i tcp:3306 |wc -l ` -gt 0 ] 

# remote
# if [ `nc -w 2 10.0.0.52 3306 &>/dev/null && echo OK|grep OK |wc -l` -gt 0 ]
if [ `nmap 10.0.0.52 -p 3306 2>/dev/null |grep open |wc -l` -gt 0 ]
	then 
		echo "mysql is running."
else 
	echo "mysql is stoped."
	echo "mysql will be started.starting..."
	systemctl start mysqld
fi

检查web服务进程

curl -I -s -o /dev/null -w "%{http_code}\n" http://10.0.0.71 -- 获取http_code
[root@zabbix scripts]# cat check_web.sh 
#!/bin/bash

if [ `curl -I http://10.0.0.71 2>/dev/null |head -1|grep 200 |wc -l` -eq 1 ] 
# if [ "`curl -s  http://10.0.0.71 &>/dev/null  && echo $?`" = "0"  ]
# if [ "`curl -s  http://10.0.0.71`" = "bbs..."  ]
#if [ "`curl -I -s -o /dev/null -w "%{http_code}\n" http://10.0.0.71`" = "200" ]
    then
	echo "httpd is running."
else
    echo "httpd is stopped."
fi

if 多分支实例3:数值比较大小

[root@zabbix scripts]# cat com_if.sh 
#!/bin/bash

read -p "pls input two nums:" num1 num2
a=$num1
b=$num2

## no.1 -- check num of args
if [ -z "$a" -o -z "$b" ] ;then
    echo "USAGE: sh "$0" num1 num2"
    exit 1
fi
## no.2 -- check int of first arg
if [ "`echo "$a" | sed -r ‘s/[^0-9]//g‘`" != "$a" ] ;then
    echo "first arg must be int,please input a intger."
    exit 2
fi
## -- check int of second arg 
if [ !"`echo "$b"|sed -r ‘s/[^0-9]//g‘`" = "$b" ] ;then
    echo "second arg must be int,please input a intger."
    exit 3
fi
## no.3 compare
if [ "$a" -eq "$b" ] ;then
    echo "$a = $b"
    exit 0
elif
[ "$a" -lt "$b" ] ;then
    echo "$a < $b"
    exit 0
else
    echo "$a > $b"
    exit 0
fi

范例4:传参方式添加用户

  • 题目:实现通过传参的方式往/etc/user.conf里添加用户。具体要求你如下:
  1. 命令用法:
    USAGE:sh adduser {-add|-del|-search} username
  2. 传参要求:
    如果参数为-add时,表示添加后面接的用户名;
    如果参数为-del时,表示删除后面接的用户名;
    如果参数为-search,表示查找后面接的用户名。
  3. 如果有同名的用户则不能添加,没有对应用户则无需删除,查找到用户以及没有用户时给出明确提示。
  4. /etc/user.conf不能被所有外部用户直接删除及修改。
  • 参考答案:
。。

扩展:MySQL进程监控

1. 根据MySQL端口号监控MySQL(本地)

  • 说明:本地监控,端口在,服务也可能不正常。例如:负载很高,CPU很高,连接数满等。
  • 端口也可以远程监控
  1. 本地:
    netstat -llntup|grep 3306|wc -l
    lsof -i:3306|wc -l
  2. 远程:
    telnet /nc /nmap
    telnet-nc-nmap:查看远端的端口是否通畅3个简单实用案例!

2.根据MySQL进程监控MySQL(本地)

  • 说明:本地监控,进程在,服务也可能不正常。例如:负载很高,CPU很高,连接数满等。
  • 进程也可以远程监控,例如:通过ssh key expect
ps -ef|grep mysql|grep -v grep|wc -l
ps -ef|grep [m]ysql|wc -l

3.通过MySQL客户端命令及用户账户连接MySQL

通过MySQL客户端命令及用户账户连接MySQL,然后根据返回命令状态
或返回内容确认MySQL是否正常(本地和远程连接判断)

  • 必须要有MySQL客户端,要有数据的账号和密码,及连接数据库主机授权。
mysql -uroot -ppassword -e "select version();" &>/dev/null
## 或者查一个表返回字符串

4.通过php/java程序URL方式监控MySQL(推荐)

  • 说明:此种方式最接近模拟用户访问,效果最好。
  • 报警的最佳方式不是服务开启了,而是网站的用户是否还访问正常。

5. 以上四种方法的综合运用。

  • 思考更多方法:如mysql status,socket,rpcbind等等。

shell 编程 01 -- 常用操作符 及 if 条件句介绍与应用

上一篇:Linux服务器上的node进程频繁被杀解决方法


下一篇:Jenkins(7)- 解决Linux下忘记Jenkins密码