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,小于等于 |
提示:工作中尽量不要使用双重括号,双重括号是按位比较
逻辑操作符
在[]和test中使用的逻辑操作符 | 在[[]]中使用的逻辑操作符 | 说明 |
---|---|---|
-a | && | and,与,两端都为真,则真 |
-o | || | or,或,两端有一个真则真 |
! | ! | not,非,相反则为真 |
实例1:数值比较大小
数值比较大小,不同方法实现
解答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服务
-
参考答案:大战前的热身准备
[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的方式判断,如果进程没起,则启动进程。
-
扩展了解:
- 监控web服务是否正常,不低于5中思路
- 监控db服务是否正常,不低于5中思路
方法:
-
端口
本地:netstat 、ss、lsof
远程:telnet、nmap、nc
telnet-nc-nmap:查看远端的端口是否通畅3个简单实用案例! -
进程(本地):ps -ef|grep [n]ginx|wc -l
-
wget、curl(http方式,判断根据返回值或返回内容)
-
header(http),(http方式,根据状态码判断)
-
数据库特有:通过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里添加用户。具体要求你如下:
- 命令用法:
USAGE:sh adduser {-add|-del|-search} username - 传参要求:
如果参数为-add时,表示添加后面接的用户名;
如果参数为-del时,表示删除后面接的用户名;
如果参数为-search,表示查找后面接的用户名。 - 如果有同名的用户则不能添加,没有对应用户则无需删除,查找到用户以及没有用户时给出明确提示。
- /etc/user.conf不能被所有外部用户直接删除及修改。
- 参考答案:
。。
扩展:MySQL进程监控
1. 根据MySQL端口号监控MySQL(本地)
- 说明:本地监控,端口在,服务也可能不正常。例如:负载很高,CPU很高,连接数满等。
- 端口也可以远程监控
- 本地:
netstat -llntup|grep 3306|wc -l
lsof -i:3306|wc -l - 远程:
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等等。