1、case语句

1.1 概述

case语句属于条件分支语句,一般用于实现有多种选择的情况,比如:菜单功能

1.2 格式

case语句格式如下:

case "变量" in
   条件)
   命令1
   ;;
   条件)
   命令2
   ;;
   *)
   命令3
esac

例如:

[root@m01 /server/script/devops-shell]#vim 21.case.sh
#1、vars
cat << EOF
  -1 138套餐  4g流量100分钟
  -2 238套餐  10g流量200分钟
  其他 错误
EOF
read num
#2、判断
case "$num" in
  1)
   echo "138套餐"
   ;;
  2)
   echo "238套餐"
   ;;
  *)
   echo "选择错误"
esac

测试:

[root@m01 /server/script/devops-shell]#sh 21.case.sh
  -1 138套餐  4g流量100分钟
  -2 238套餐  10g流量200分钟
  其他 错误
1
138套餐
[root@m01 /server/script/devops-shell]#sh 21.case.sh
  -1 138套餐  4g流量100分钟
  -2 238套餐  10g流量200分钟
  其他 错误
3
选择错误
[root@m01 /server/script/devops-shell]#

案例1:判断用户输入的是yes,还是no

输入yes,y,Y,Yes,都表示yes

输入no,n,N,No,都表示no

[root@m01 /server/script/devops-shell]#vim 22.case_yes_no.sh
#1、vars
read -p "请输入yes或no:" yesno
#2、case
case "$yesno" in
  yes|y|Y|y) echo yes;;
  no|No|n|N) echo no;;
  *)      echo error
          exit 1
esac

案例02:书写服务管理脚本,实现脚本开、关、重启与状态检查

不太推荐read方式

管理:nginxWebUI-3.4.0.jar

环境准备:jdk

[root@m01 /app/code/ngxwebui]#pwd
/app/code/ngxwebui
[root@m01 /app/code/ngxwebui]#ls
nginxWebUI-3.4.0.jar
[root@m01 /app/code/ngxwebui]#

提示:

服务类的脚本的名称尽量不要包含服务名称,否则,过滤的时候会把脚本过滤出来,还得排除

脚本:

#1、vars
choice=$1
codedir=/app/code/ngxwebui/
javaname=nginxWebUI-3.4.0.jar
#2、case
case "$choice" in
    start)
       #判断,如果没有运行,则启动
       java_process_count=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}' | wc -l`
       if [ $java_process_count -eq 0 ];then
           echo start
           cd ${codedir}
           nohup java -jar -Dfile.encoding=UTF-8 $javaname --server.port=8848 --project.home=$codedir &> /dev/null &
       fi 
       ;;
    stop)
       #如果进程已启动,则执行停止
       java_process_count=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}' | wc -l`
       if [ $java_process_count -eq 1 ];then
          echo stop
          javapid=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}'`
          kill $javapid
       fi
       ;;
    restart)
       echo restart
       #重启就是,停止再开启,$0脚本名称
       sh $0 stop
       sleep 1 #由于Java关闭需要时间,这里设置等待1秒,确保让它彻底关闭,再启动
       sh $0 start
       ;;
    status)
       echo status
       #判断服务是否运行
       java_process_count=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}' | wc -l`
       if [ $java_process_count -eq 1 ];then
          javapid=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}'`
          echo "$javaname is running,pid: $javapid"
       else
          echo "$javaname is stopped"
       fi
       ;;
    *)
       echo "Usage: $0 start|stop|restart|status"
       exit 1
esac

2、函数

2.1 概述

把一堆代码,起个名字

对脚本中重复使用到的代码,设置函数,精简脚本的内容

2.2 格式与使用

格式1:

function  函数名() {
  命令
   return n #函数返回值
}

格式2:

function  函数名 {
  命令
   return n #函数返回值
}

格式3(推荐使用):

函数名() {
  命令
  return  n
}

使用函数:函数名,注意不需要加()

例如:

[root@m01 /server/script/devops-shell]#vim 24.function.sh
function show() {
  echo "funcion..."
  echo "hello world"
}

show  #调用函数

优化前面的服务脚本管理

[root@m01 /server/script/devops-shell]#vim 25.func.system_jar.sh
#1、vars
choice=$1
codedir=/app/code/ngxwebui/
javaname=nginxWebUI-3.4.0.jar

#2、函数定义
start() {
   #判断,如果已经运行了,则不执行,没有运行,则启动
   java_process_count=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}' | wc -l`
       if [ $java_process_count -eq 0 ];then
           echo start
           cd ${codedir}
           nohup java -jar -Dfile.encoding=UTF-8 $javaname --server.port=8848 --project.home=$codedir &
       fi 
}
stop() {
         #如果进程已启动,则执行停止
       java_process_count=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}' | wc -l`
       if [ $java_process_count -eq 1 ];then
          echo stop
          javapid=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}'`
          kill $javapid
       fi
}
restart() {
       echo restart
       #重启就是,停止再开启,$0脚本名称
       stop
       sleep 1  #设置休眠时间为1秒,为了让它彻底关闭
       start
}
status() {
       echo status
       #判断服务是否运行
       java_process_count=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}' | wc -l`
       if [ $java_process_count -eq 1 ];then
          javapid=`ps -ef | grep "$javaname" | grep -v grep | awk '{print $2}'`
          echo "$javaname is running,pid: $javapid"
       else
          echo "$javaname is stopped"
       fi
}

#3、main
main() {
  case "$choice" in
      start)
         start
         ;;
      stop)
         stop
         ;;
      restart)
        restart
         ;;
      status)
        status
         ;;
      *)
         echo "Usage: $0 start|stop|restart|status"
         exit 1
  esac
  }

  main

2.3 函数传参

函数传参与脚本传参类似,使用$xxx是形式

位置参数shell脚本中函数中
$n脚本的第n个参数函数的第n个参数
$0脚本的名称脚本的名称
$#脚本的参数个数函数的参数个数
$@、$*脚本的所有参数函数的所有参数

使用格式: 函数名 参数

案例1:函数传参案例

[root@m01 /server/script/devops-shell]#vim 26.func.sh
show() {
  echo $1
}
show hello
show $*

#执行
[root@m01 /server/script/devops-shell]#sh 26.func.sh  world
hello
world
[root@m01 /server/script/devops-shell]#

3、个人函数库

把脚本中常用到的功能创建成函数

3.1 颜色

Linux命令行给字体加颜色的命令为:

echo -e "\E[1;31m红色字world\E[0m"
echo -e "\033[31m红色字world\033[0m"

效果:

解释:

\E或\033:表示要开启这种功能
[1;31m
  [效果;颜色m
\E[0m   颜色设置结束

上述命令中,echo  -e 可以识别转移字符(\n \t)
Linux中回车:\n
windows中回车:\r\n

10种效果

颜色:

[root@m01 ~]#for n in {30..50}; do echo -e "\E[1;${n}mHello World\E[0m"; done

如下:

写成函数:例如

redecho() {
  echo -ne "\E[5;31m"  #-n:输出不换行
  echo -n "$@"
  echo -e "\E[0m"
}

greenecho() {
  echo -ne "\E[1;32m"
  echo -n "$@"
  echo -e "\E[0m"
}

blueecho() {
  echo -ne "\e[1;34m"
  echo -n "$@"
  echo -e "\e[0m"
}

案例1:自定义颜色函数

脚本:

[root@m01 /server/script/devops-shell]#vim func_diy.sh
#1、颜色类函数
redecho() {
  echo -ne "\E[1;31m"  #-n:输出不换行
  echo -n "$@"
  echo -e "\E[0m"
  # echo -e "\e[5;31m $@ \e[0m"
}

greenecho() {
  echo -ne "\E[1;32m"
  echo -n "$@"
  echo -e "\E[0m"
}

blueecho() {
  echo -ne "\e[1;34m"
  echo -n "$@"
  echo -e "\e[0m"

使用:

[root@m01 /server/script/devops-shell]# . func_diy.sh

如图:

应用案例:

[root@m01 /server/script/devops-shell]#vim 28.ping_url_funcs.sh
#1、vars
if [ -f /server/script/devops-shell/func_diy.sh ];then
   . /server/script/devops-shell/func_diy.sh
else
   echo func_diy.sh not found
   exit 1
fi
read -p '请输入域名:' url
#2、ping
ping -c 3 $url &> /dev/null
#3、判断
if [ $? -eq 0 ]
then
   greenecho "域名$url可以ping通。"
else
   redecho "域名$url ping不通"
fi

执行脚本,效果:

颜色的更多说明:https://man7.org/linux/man-pages/man4/console_codes.4.html

3.2 判断

判断参数个数

判断参数是否为数字

判断命令返回值

3.3 日志

给脚本创建日志

检查脚本关键步骤,执行情况。方便后期调试

比如:

定义名为log函数
使用:log 警告级别  "执行情况与做啥"  日志文件
日志内容:
年-月-日 时:分:秒[错误级别] "执行情况与做啥"
日志文件:/var/log/xxx.log

脚本:

[root@m01 /server/script/devops-shell]#vim func_log.sh
#日志函数
log() {
  #vars
  level=$1
  msg=$2
  logfile=$3
  time=`date +%F_%T`
  #检查日志目录
  logdir=`dirname $logfile` #dirname取出目录,basename取出文件名
  #logdir=${logfile%/*}
  [ -d $logdir ] || mkdir -p $logdir
  #写入日志
  echo "[$time] [$level] [$msg]" >> $logfile
}

测试:

[root@m01 /server/script/devops-shell]#. func_log.sh 
[root@m01 /server/script/devops-shell]#log ERROR 脚本运行正常 /var/log/test.log
[root@m01 /server/script/devops-shell]#cat /var/log/test.log
[2023-07-20_22:11:14] [ERROR] [脚本运行正常]
[root@m01 /server/script/devops-shell]#

4、必知必会命令

4.1 命令概述

脚本常用监控命令用途命令
端口一般用于检查端口是否存在,是否能连接是否存在:ss -lntup | grep 端口
netstat -lntup | grep 端口
lsof -i:端口
是否能访问:telnet、nc、nmap
进程检查进程状态ps、top、iotop
网络检查连通性ping、iftop(流量)、dig(DNS)…
webhttp请求curl、wget
系统全能atop(all)

4.2 端口检查

1)是否存在

比如,检查80端口是否存在

[root@m01 ~]#ss -tnlup | grep 80
[root@m01 ~]#netstat -lntup | grep 80
[root@m01 ~]#lsof -i:80
2)能否访问

telnet:

-e:指定逃脱字符,遇到这个字符相当于ctrl+c

[root@m01 ~]#echo q | telnet -eq 192.168.10.61 80
Telnet escape character is 'q'.
Trying 192.168.10.61...
telnet: connect to address 192.168.10.61: Connection refused
[root@m01 ~]#echo $?
1
[root@m01 ~]#

执行命令结果是1,说明80端口不能访问

nc:

-z:无io模式,用于检查端口是否连通

[root@m01 ~]#nc -z 192.168.10.61 22
[root@m01 ~]#echo $?
0
[root@m01 ~]#

执行命令结果是0,说明22端口是通的

nmap:

[root@m01 ~]#nmap -p 192.168.10.61 22
PORT   STATE SERVICE
22/tcp open  ssh
[root@m01 ~]#

结果显示22端口是通的

4.3 进程检查

用ps、top命令

4.4 网络检查

ping命令:-c次数,ping几次,-w timeout 超时时间,等待响应的超时时间

iftop命令

4.5 web与api测试命令

1)curl命令
-v -L 跟随跳转
-H 修改请求头
-I 只显示响应头
-w  按照指定格式输出
-o 输出到指定文件或空
-s 一般用于管道,需要加上

使用:

#1、curl 获取状态码
# -s slient,安静模式,如果不适用,默认输出下载进度
# -o  curl的输出到指定位置的文件
# -w 按照指定格式与内容输出,%{http_code}状态码,更多格式:man curl 搜索variable

获取状态码:

[root@m01 ~]#curl -s -w '%{http_code}\n' -o /dev/null www.baidu.com
200
[root@m01 ~]#

获取响应头:

[root@m01 ~]#curl -I www.baidu.com

POST:

输入用户名密码(ak id和securet)获取令牌token
通过令牌访问资源
-X 请求方法
-H 修改请求头
-d 请求报文主体
[root@m01 ~]#curl -s  -X POST -H Content-Type:application/json-rpc 192.168.10.61/api_jsonrpc.php -d '{
 "jsonrpc":"2.0"
"method":"user.login",
"params": {
  "user": "Admin",
   "password":"zabbix"
},
"id":1,
 "auth":null
}'
[root@m01 ~]#

2)wget命令

-t 失败后,重复尝试次数
-T timeout,超时时间
-q 不显示wget输出
--spider 不下载文件,仅访问

例如:

[root@m01 ~]#wget -t 3 -T 1 -q --spider www.baidu.com

4.6 全能信息

atop安装:

[root@m01 ~]#yum install -y atop
[root@m01 ~]#systemctl enable atop
[root@m01 ~]#systemctl start atop

4.7 案例

案例1:检查指定的地址的端口是否可以访问

[root@m01 /server/script/devops-shell]#vim 29.check_port.sh
#1、vars
url=$1
port=$2
func=/server/script/devops-shell/funcs_diy.sh
logfunc=/server/script/devops-shell/funcs_log.sh
[ -f $logfunc ] && . $logfunc
if [ -f $func ];then
 . $func
else
   echo $func not found
   exit 1
fi
#2、ping
ping -c1 $url  &> /dev/null  || {
  redecho "$url无法访问"
  exit 1
}

#3、telnet
echo q | telnet -eq $url $port &> /dev/null
if [ $? -eq 0 ];then
  greenecho "$url $port 可以访问"
  log INFO "$url $port OK" /var/log/port.log
else
  redecho "$url $port 无法访问"
  log ERROR "$url $port Failed" /var/log/port.log
fi

效果:

也可以使用nc:

# -w 超时时间
# -z 非交互式
if nc -w 1 -z $1 $2 ;then
   echo "地址:$1 端口:$2 is ok"
else
   echo "地址:$1 端口:$2 is failed"
fi

案例2:检查https证书是否过期,检查域名是否过期

获取ssl证书过期日期(以百度为例):

curl -Lv https://www.baidu.com -o /dev/null |& grep 'expire date'
*       expire date: Aug 06 05:16:01 2023 GMT
[root@m01 ~]#

获取域名过期日期(以百度为例):

[root@m01 ~]#whois baidu.com | grep -i expiry
   Registry Expiry Date: 2026-10-11T11:05:17Z
[root@m01 ~]#

把日期转为秒:

[root@m01 ~]#date +%s -d 'Aug 06 05:16:01 2023 GMT'
1691298961
[root@m01 ~]#

把当前日期转为秒,然后相减就得到,还有多少秒过期。再把秒转为日即可。

把ssl证书过期日期转为秒:

[root@m01 ~]#date -d "`curl -Lv https://www.baidu.com -o /dev/null |& grep 'expire date' | awk -F'date:' '{print $2}'`" +%s
1691298961
[root@m01 ~]#

把域名过期日期转为秒:

[root@m01 ~]# date -d "`whois baidu.com | grep -i expiry | awk -F'Date:' '{print $2}'`" +%s
1791716717
[root@m01 ~]#

把当前日期转为秒:

[root@m01 ~]#date +%s
1689866683
[root@m01 ~]#

分别相减即可。

最终脚本如下:

[root@m01 /server/script/devops-shell]#vim 30.chck_url_guoqi.sh
#1、vars
export LANG=en_US.UTF-8
url=$1
#加载自定义的函数文件
func=/server/script/devops-shell/funcs_diy.sh
log_func=/server/script/devops-shell/funcs_log.sh
[ -f $log_func ] && . $log_func

if [ -f $func ];then
  . $func
else
    echo "$func not found"
    exit 1
fi
#检查
check_error() {
 #2、check url
 [[ $url =~ ^[a-zA-Z0-9]+\.[a-zA-Z]+$ ]] || {
     redecho "$url 不可用"
  }
 #3、check_net
 ping -c3 -i0.5 $url &>/dev/null || {
    redecho "$url 无法访问"
    exit 2
  }
 #4、check_cmd
 which whois &>/dev/null || {
    redecho "whois命令不存在"
    exit 3
  }
}

#检查域名过期
check_domain() {
   #域名过期时间
   expire_date=`whois $url | grep -Ei "expiry|expiration" | awk -F'Date: ' '{print $2}'`
   #域名过期时间转为秒
   expire_date_second=`date -d "${expire_date}" +%s`
   #当前时间转为秒
   date_now_second=`date +%s`
   #两个秒数相减,除以60、60、24转为天数
   date_expire_days=`echo "(${expire_date_second} - ${date_now_second})/60/60/24" | bc`
   if [ ${date_expire_days} -le 30 ];then
     redecho "$url 即将过期,还有${date_expire_days}天"
     log ERROR "$url 即将过期,还有${date_expire_days}天" /var/log/url.log
   else
     greenecho "$url 可以安全使用,还有${date_expire_days}天"
     log INFO "$url 可以安全使用,还有${date_expire_days}天" /var/log/url.log
   fi
} 

#检查证书过期
check_https() {
   #域名过期时间
   expire_date=`curl -v https://www.${url} |& grep -Ei "expire|expiration" | awk -F'date: ' '{print $2}'`
   #域名过期时间转为秒
   expire_date_second=`date -d "${expire_date}" +%s`
   #当前时间转为秒
   date_now_second=`date +%s`
   #两个秒数相减,除以60、60、24转为天数
   date_expire_days=`echo "(${expire_date_second} - ${date_now_second})/60/60/24" | bc`
   if [ ${date_expire_days} -le 30 ];then
     redecho "$url https证书即将过期,还有${date_expire_days}天"
     log ERROR "$url https证书即将过期,还有${date_expire_days}天" /var/log/url.log
   else
     greenecho "$url https证书 可以安全使用,还有${date_expire_days}天"
     log INFO "$url https证书 可以安全使用,还有${date_expire_days}天" /var/log/url.log
   fi
}
#main
main() {
  check_error
  check_domain
  check_https
}
main

测试如下图:

如果证书在本地,查看过期日期:

openssl x509 -in 证书文件  -noout -dates

notAfter就是过期日期

5、for循环

5.1 常用格式

1)格式1

最常见的格式

for  变量  in  清单(列表)
do
   命令
done

例如:

for n  in 1 2 3 4 5
do
  ech $n
done

###########

for n in {1..10}
do
  ech $n
done

##########

for n in {1..3} `ls /etc/|head -5`  `seq 5`
do
  echo $n
done

例如:计算1到100的和

sum=0
for n in {1..100}
do
  sum=`echo "$sum+$n" | bc `
done
echo $sum

例如:

[root@m01 ~]#for n in `ls /etc/ | head -5`;do echo $n;done
abrt
adjtime
aliases
aliases.db
alternatives
[root@m01 ~]#

2)格式2

类似C语言格式的for循环,例如:

for((i=1;i<=10;i++))
do
  echo $i
done

5.2 应用场景

格式1:通用场景,大部分场景可以使用

格式2:对数组循环使用

5.3 案例

案例:使用for循环在/test/目录下,通过随机小写1个字母加_test批量创建html文件。

比如文件名:adbjdueglv_test.html

生成随机字符:

1、uuidgen

2、mkpasswd  -l 10 -d 0 -s 0 -C 0
-l:长度
-d:数字数量
-s:special,特殊字符
-C:大写字母
-c:小写字母

3、tr命令
tr  -cd 'a-z' </dev/urandom | head -c10
-c:取反
-d:删除
/dev/urandom 字符设备,生成随机字符

4、date +%N | md5sum | cut -c1-10
date +%N | md5sum | head -c10
%N:纳秒

5、echo $RANDOM
范围:0-32767
echo $((RANDOM+1000000000))

脚本:

[root@m01 /server/script/devops-shell]#vim 31.random_files.sh
for n in {1..10}
do
  str=`mkpasswd  -l 10 -s 0`
  filename=${str}_test.html
  touch /tmp/$filename
done

6、while循环

6.1 格式

通用格式:

while  条件
do
  命令
done

温馨提示:

while循环只会在满足条件后运行

案例01:使用while循环输出1-10

i=1
while [ $i -le 10 ]
do
  echo $i
  let i++
done

计算1到100的和:

[root@m01 ~]#echo {1..100} | tr ' ' '+' | bc
5050
[root@m01 ~]#

6.2 死循环

死循环:一直循环,直到用户手动中止或满足指定条件后退出

while  true 或 while  :
do
  命令
done

例如:

[root@m01 ~]#while true ; do echo true; sleep 5 ;date ;done
true
Sat Jul 22 09:24:53 CST 2023
true
Sat Jul 22 09:24:58 CST 2023

案例:生产随机数字,判断数字是什么(1-100)

如果输入的数字比随机数大,提示大了。小,则提示小了。等于,提示等于,并退出程序

[root@m01 /server/script/devops-shell]#vim 34.guess_num.sh
#1、random
num=$((RANDOM%100+1)) #RANDOM范围:1-32767,对100取余,再加1,得到1-100的数
i=0
percent() {
  if [ $i -le 5 ];then
    echo "超过了99.99%的人,猜了$i次"
  elif [ $i -le 10 ];then
    echo "超过了90%的人,猜了$i次"
  else
    echo "超过了85%的人,猜了$i次"
  fi
}
input() {
  #2、vars
  read -p "输入数字:" guess
}
check() {
  #3、check
  expr $guess + 1 &> /dev/null
  [ $? -gt 1 ] && {
    echo "请输入数字,重来"
    exit 1
  }
}
compare() {
#4、compare
  if [ $guess -eq $num ];then
    echo "猜对了"
    percent
    exit
  elif [ $guess -gt $num ];then
    echo "数字大了"
  else
    echo "数字小了"
  fi
}
main() {
#5、while
  while true
  do
     input
     let i++
     check
     compare
  done
}
main

6.3 while读取文件内容

方式1:采用exec读取文件内容,然后进入while循环

exec<FILE
while read line
do
   命令
   echo $line
done

方式2:使用cat读取文件,然后通过管道进入循环。不适用于有变量传递的场景

cat  FILE | while read line
do
   命令
   echo $line
done

方式3:在while循环结尾done通过重定向输入

while read line
do
   命令
   echo $line
done<FILE

案例01:通过while read方式,统计ip.txt文件,ping下

#准备ip.txt文件
[root@m01 /server/script/devops-shell]#echo 192.168.10.61 >> ip.txt
[root@m01 /server/script/devops-shell]#echo 192.168.10.1 >> ip.txt
[root@m01 /server/script/devops-shell]#echo 192.168.10.2 >> ip.txt
[root@m01 /server/script/devops-shell]#echo 192.168.10.7 >> ip.txt
[root@m01 /server/script/devops-shell]#echo www.baidu.com >> ip.txt
[root@m01 /server/script/devops-shell]#echo baidu.com >> ip.txt

脚本如下:

[root@m01 /server/script/devops-shell]#vim 35.while_read_ping_ip.sh
#1、vars
ipfile=/server/script/devops-shell/ip.txt
#2、while
while read line
do
  ping -c1 -i0.5 $line &> /dev/null
 if [ $? -ne 0 ];then
  echo "$line,网络不通"
 else
  echo "$line,网络通"
 fi
done<$ipfile

方式2、方式3的区别:

[root@m01 /server/script/devops-shell]#vim while_read.sh
file=/server/script/devops-shell/ip.txt
i=0
j=0

#1、方法2:while+cat
echo "方式2:while + cat"
cat $file | while read ip
do
  echo $ip
  let i++
done
echo "次数:$i"

#2、方式3:while + 输入
echo "方式3:while + 输入"
while read ipa
do
  echo $ipa
  let j++
done<$file
echo "次数:$j"

测试结果:

显然,区别在于变量的作用范围,方式2的变量,离开开while循环体,则无法获取循环中修改过的值。

原因:

方式2:while read + 管道。在运行的时候因为管道,创建1个子shell,变量都存放在子shell中,子shell运行完成,消失了,而变量也没了

方式3:while + 输入重定向。运行的时候是与当前脚本在同一个shell中,所以变量保存了,可以继续使用。

在不涉及变量的情况下,方式2、方式3的效果是一样的如果涉及变量,要使用方式3

案例02:分析NGINX访问日志(access.log),找出访问量最高的前5个ip及访问次数,ip访问次数大于200的,则通过防火墙屏蔽该ip

防DOS拒绝式攻击

DDOS分布式拒绝式服务攻击

CC基于http请求攻击

access.log日志内容格式如下:

101.226.61.184 - - [22/Nov/2015:11:02:00 +0800] "GET /mobile/sea-modules/gallery/zepto/1.1.3/zepto.js HTTP/1.1" 200 24662 

以空格分隔,第一列就是ip

脚本:

[root@m01 /server/script/devops-shell]#vim 36.dos.sh
#1、vars
logfile=/server/script/files/access.log
tmpfile=/server/script/files/tmp.txt
#2、sort-uniq
awk '{print $1}' $logfile | sort | uniq -c | sort -rnk1 | head -5 >$tmpfile
#3、while
while read line
do
  ip=`echo $line | awk '{print $2}'`
  cnt=`echo $line | awk '{print $1}'`
  iptables_cnt=`iptables -t filter -nL | grep -w $ip | wc -l`
  if [ $cnt -ge 200 -a $iptables_cnt -eq 0 ];then 
  #判断次数大于200,且未屏蔽的才屏蔽,如果已经屏蔽则不需重复屏蔽
     iptables -t filter -I INPUT -s $ip -j DROP
  fi
done<$tmpfile

7、do-until循环

无论条件是否满足,都会执行1次。

直到型循环:一直循环,直到条件不满足

until 条件
do
  命令
done

8、循环小结

循环格式应用场景
forfor 变量 in 清单(列表);do 命令 ;done大部分使用
for((i=1;i<=10;i++));do 命令; done数组循环
whilewhile 条件;do 命令; done死循环、读文件
untiluntil 条件;do 命令; done很少用