第十二章 Shell脚本编写及常见面试题(二)

简介:

本章目录:

wKiom1knwb2hBosbAAAjiZOplaQ602.png

12.11 屏蔽网站访问频繁的IP

1)屏蔽每分钟访问超过200的IP

方法1:以Nginx日志作为测试

1
2
3
4
5
6
7
8
DATE=$( date  +%d/%b/%Y:%H:%M)
ABNORMAL_IP=$( tail  -n5000 access.log | grep  $DATE | awk  '{a[$1]++}END{for(i in a)if(a[i]>100)print i}' )
#先tail防止文件过大,读取慢,数字可调整每分钟最大的访问量。awk不能直接过滤日志,因为包含特殊字符。
for  IP  in  $ABNORMAL_IP;  do
     if  [ $(iptables -vnL | grep  -c  "$IP" ) - eq  0 ];  then
         iptables -I INPUT -s $IP -j DROP
     fi
done

方法2:通过建立连接数

1
2
3
4
5
6
7
ABNORMAL_IP=$( netstat  -an | awk  '$4~/:80$/ && $6~/ESTABLISHED/{gsub(/:[0-9]+/,"",$5);{a[$5]++}}END{for(i in a)if(a[i]>100)print i}' )
#gsub是将第五列(客户端IP)的冒号和端口去掉
for  IP  in  $ABNORMAL_IP;  do
     if  [ $(iptables -vnL | grep  -c  "$IP" ) - eq  0 ];  then
         iptables -I INPUT -s $IP -j DROP
     fi
done

2)屏蔽每分钟SSH暴力破解超过10次的IP

方法1:通过lastb获取登录状态:

1
2
3
4
5
6
7
DATE=$( date  + "%a %b %e %H:%M" #星期月天时分  %e单数字时显示7,而%d显示07
ABNORMAL_IP=$(lastb | grep  "$DATE"  | awk  '{a[$3]++}END{for(i in a)if(a[i]>10)print i}' )
for  IP  in  $ABNORMAL_IP;  do
     if  [ $(iptables -vnL | grep  -c  "$IP" ) - eq  0 ];  then
         iptables -I INPUT -s $IP -j DROP
     fi
done

方法2:通过日志获取登录状态

1
2
3
4
5
6
7
8
DATE=$( date  + "%b %d %H" )
ABNORMAL_IP= "$(tail -n10000 /var/log/auth.log |grep " $DATE " |awk '/Failed/{a[$(NF-3)]++}END{for(i in a)if(a[i]>5)print i}')"
for  IP  in  $ABNORMAL_IP;  do
     if  [ $(iptables -vnL | grep  -c  "$IP" ) - eq  0 ];  then
         iptables -A INPUT -s $IP -j DROP
         echo  "$(date +" %F %T ") - iptables -A INPUT -s $IP -j DROP"  >>~ /ssh-login-limit .log
     fi
done

12.12 判断输入是否为IP

方法1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function  check_ip(){
     IP=$1
     VALID_CHECK=$( echo  $IP| awk  -F.  '$1<=255&&$2<=255&&$3<=255&&$4<=255{print "yes"}' )
     if  echo  $IP| grep  -E  "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" > /dev/null then
         if  [ $VALID_CHECK ==  "yes"  ];  then
             echo  "$IP available."
         else
             echo  "$IP not available!"
         fi
     else
         echo  "Format error!"
     fi
}
check_ip 192.168.1.1
check_ip 256.1.1.1

方法2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function  check_ip(){
     IP=$1
     if  [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]];  then
         FIELD1=$( echo  $IP| cut  -d. -f1)
         FIELD2=$( echo  $IP| cut  -d. -f2)
         FIELD3=$( echo  $IP| cut  -d. -f3)
         FIELD4=$( echo  $IP| cut  -d. -f4)
         if  [ $FIELD1 - le  255 -a $FIELD2 - le  255 -a $FIELD3 - le  255 -a $FIELD4 - le  255 ];  then
             echo  "$IP available."
         else
             echo  "$IP not available!"
         fi
     else
         echo  "Format error!"
     fi
}
check_ip 192.168.1.1
check_ip 256.1.1.1

增加版:加个死循环,如果IP可用就退出,不可用提示继续输入,并使用awk判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function  check_ip(){
     local  IP=$1
     VALID_CHECK=$( echo  $IP| awk  -F.  '$1<=255&&$2<=255&&$3<=255&&$4<=255{print "yes"}' )
     if  echo  $IP| grep  -E  "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"  > /dev/null then
         if  [ $VALID_CHECK ==  "yes"  ];  then
             return  0
         else
             echo  "$IP not available!"
             return  1
         fi
     else
         echo  "Format error! Please input again."
         return  1
     fi
}
while  true do
     read  -p  "Please enter IP: "  IP
     check_ip $IP
     [ $? - eq  0 ] &&  break  ||  continue
done

12.13 判断输入是否为数字

1
2
3
4
5
6
7
8
9
10
11
12
方法1:
if  [[ $1 =~ ^[0-9]+$ ]];  then
     echo  "Is Number."
else
     echo  "No Number."
fi
方法2:
if  [ $1 -gt 0 ] 2> /dev/null then
     echo  "Is Number."
else
     echo  "No Number."
fi

方法3:

1
2
3
4
5
6
7
8
9
echo  $1 | awk  '{print $0~/^[0-9]+$/?"Is Number.":"No Number."}'   #三目运算符
12.14 找出包含关键字的文件
DIR=$1
KEY=$2
for  FILE  in  $( find  $DIR - type  f);  do
     if  grep  $KEY $FILE &> /dev/null then
         echo  "--> $FILE"
     fi
done

12.15 监控目录,将新创建的文件名追加到日志中

需安装inotify-tools软件包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/bash
MON_DIR= /opt
inotifywait -mq -- format  %f -e create $MON_DIR |\
while  read  files;  do
   echo  $files >>  test .log
done
12.16 多个网卡选择
function  local_nic() {
     local  NUM ARRAY_LENGTH
     NUM=0
     for  NIC_NAME  in  $( ls  /sys/class/net | grep  -vE  "lo|docker0" );  do
         NIC_IP=$( ifconfig  $NIC_NAME | awk  -F '[: ]+'  '/inet addr/{print $4}' )
         if  [ -n  "$NIC_IP"  ];  then
             NIC_IP_ARRAY[$NUM]= "$NIC_NAME:$NIC_IP"     #将网卡名和对应IP放到数组
             let  NUM++
         fi
     done
     ARRAY_LENGTH=${ #NIC_IP_ARRAY[*]}
     if  [ $ARRAY_LENGTH - eq  1 ];  then      #如果数组里面只有一条记录说明就一个网卡
         NIC=${NIC_IP_ARRAY[0]%:*}
         return  0
     elif  [ $ARRAY_LENGTH - eq  0 ];  then    #如果没有记录说明没有网卡
         echo  "No available network card!"
         exit  1
     else
         #如果有多条记录则提醒输入选择
         for  NIC  in  ${NIC_IP_ARRAY[*]};  do
             echo  $NIC
         done
         while  true do
             read  -p  "Please enter local use to network card name: "  INPUT_NIC_NAME
             COUNT=0
             for  NIC  in  ${NIC_IP_ARRAY[*]};  do
                 NIC_NAME=${NIC%:*}
                 if  [ $NIC_NAME ==  "$INPUT_NIC_NAME"  ];  then
                     NIC=${NIC_IP_ARRAY[$COUNT]%:*}
                     return  0
                 else
                    COUNT+=1
                 fi
             done
             echo  "Not match! Please input again."
         done
     fi
}
local_nic

如果有只有一个网卡就不选择。

12.17 查看网卡实时流量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/bash
# Description: Only CentOS6
traffic_unit_conv() {
     local  traffic=$1
     if  [ $traffic -gt 1024000 ];  then
         printf  "%.1f%s"  "$(($traffic/1024/1024))"  "MB/s"
     elif  [ $traffic -lt 1024000 ];  then
         printf  "%.1f%s"  "$(($traffic/1024))"  "KB/s"
     fi
}
NIC=$1
echo  -e  " In ------ Out"
while  true do
     OLD_IN=$( awk  -F '[: ]+'  '$0~"' $NIC '"{print $3}'  /proc/net/dev )
     OLD_OUT=$( awk  -F '[: ]+'  '$0~"' $NIC '"{print $11}'  /proc/net/dev )
     sleep  1
     NEW_IN=$( awk  -F '[: ]+'  '$0~"' $NIC '"{print $3}'  /proc/net/dev )
     NEW_OUT=$( awk  -F '[: ]+'  '$0~"' $NIC '"{print $11}'  /proc/net/dev )
     IN=$(($NEW_IN-$OLD_IN))
     OUT=$(($NEW_OUT-$OLD_OUT))
     echo  "$(traffic_unit_conv $IN) $(traffic_unit_conv $OUT)"
     sleep  1
done
# 也可以通过ficonfig命令获取收发流量
while  true do
     OLD_IN=$( ifconfig  $NIC | awk  -F '[: ]+'  '/bytes/{print $4}' )  
     OLD_OUT=$( ifconfig  $NIC | awk  -F '[: ]+'  '/bytes/{print $9}' )
     sleep  1
     NEW_IN=$( ifconfig  $NIC | awk  -F '[: ]+'  '/bytes/{print $4}' )
     NEW_OUT=$( ifconfig  $NIC | awk  -F '[: ]+'  '/bytes/{print $9}' )
     IN=$(($NEW_IN-$OLD_IN))
     OUT=$(($NEW_OUT-$OLD_OUT))
     echo  "$(traffic_unit_conv $IN) $(traffic_unit_conv $OUT)"
     sleep  1
done

12.18 MySQL数据库备份

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
DATE=$( date  +%F_%H-%M-%S)
HOST=192.168.1.120
DB= test
USER=bak
PASS=123456
MAIL= "zhangsan@example.com lisi@example.com"
BACKUP_DIR= /data/db_backup
SQL_FILE=${DB}_full_$DATE.sql
BAK_FILE=${DB}_full_$DATE.zip
cd  $BACKUP_DIR
if  mysqldump -h$HOST -u$USER -p$PASS --single-transaction --routines --triggers -B $DB > $SQL_FILE;  then
     zip $BAK_FILE $SQL_FILE &&  rm  -f $SQL_FILE
     if  [ ! -s $BAK_FILE ];  then
             echo  "$DATE 内容"  | mail -s  "主题"  $MAIL
     fi
else
     echo  "$DATE 内容"  | mail -s  "主题"  $MAIL
fi
find  $BACKUP_DIR -name  '*.zip'  -ctime +14 - exec  rm  {} \;

12.19 Nginx启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/bin/bash
# Description: Only support RedHat system
/etc/init .d /functions
WORD_DIR= /data/project/nginx1 .10
DAEMON=$WORD_DIR /sbin/nginx
CONF=$WORD_DIR /conf/nginx .conf
NAME=nginx
PID=$( awk  -F '[; ]+'  '/^[^#]/{if($0~/pid;/)print $2}'  $CONF)
if  [ -z  "$PID"  ];  then
     PID=$WORD_DIR /logs/nginx .pid
else
     PID=$WORD_DIR/$PID
fi
stop() {
     $DAEMON -s stop
     sleep  1
     [ ! -f $PID ] && action  "* Stopping $NAME"   /bin/true  || action  "* Stopping $NAME"  /bin/false
}
start() {
     $DAEMON
     sleep  1
     [ -f $PID ] && action  "* Starting $NAME"   /bin/true  || action  "* Starting $NAME"  /bin/false
}
reload() {
     $DAEMON -s reload
}
test_config() {
     $DAEMON -t
}
case  "$1"  in
     start)
         if  [ ! -f $PID ];  then
             start
         else
             echo  "$NAME is running..."
             exit  0
         fi
         ;;
     stop)
         if  [ -f $PID ];  then
             stop
         else
             echo  "$NAME not running!"
             exit  0
         fi
         ;;
     restart)
         if  [ ! -f $PID ];  then
             echo  "$NAME not running!" 
             start
         else
             stop
             start
         fi
         ;;
     reload)
         reload
         ;;
     testconfig)
         test_config
         ;; 
     status)
         [ -f $PID ] &&  echo  "$NAME is running..."  ||  echo  "$NAME not running!"
         ;;
     *)
         echo  "Usage: $0 {start|stop|restart|reload|testconfig|status}"
         exit  3
         ;;
esac

12.20 选择SSH连接主机

写一个配置文件保存被监控主机SSH连接信息,文件内容格式:主机名 IP User Port

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
PS3= "Please input number: "
HOST_FILE=host
while  true do
     select  NAME  in  $( awk  '{print $1}'  $HOST_FILE) quit;  do
         [ ${NAME:=empty} ==  "quit"  ] &&  exit  0
         IP=$( awk  - v  NAME=${NAME}  '$1==NAME{print $2}'  $HOST_FILE)
         USER=$( awk  - v  NAME=${NAME}  '$1==NAME{print $3}'  $HOST_FILE)
         PORT=$( awk  - v  NAME=${NAME}  '$1==NAME{print $4}'  $HOST_FILE)
         if  [ $IP ];  then
             echo  "Name: $NAME, IP: $IP"
             ssh  -o StrictHostKeyChecking=no -p $PORT -i id_rsa $USER@$IP   # 密钥登录
             break
         else
             echo  "Input error, Please enter again!"
             break
         fi
     done
done

本文转自 李振良OK 51CTO博客,原文链接:http://blog.51cto.com/lizhenliang/1929770,如需转载请自行联系原作者

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
17天前
|
弹性计算 Shell Perl
ecs服务器shell常用脚本练习(二)
【4月更文挑战第1天】shell代码训练(二)
102 1
|
20天前
|
Java Shell
SpringBoot启动脚本Shell
SpringBoot启动脚本Shell
15 0
|
1天前
|
Shell
Shell脚本之流程控制语句
Shell脚本之流程控制语句
|
2天前
|
JSON 运维 监控
训练shell常用脚本练习(三)
【4月更文挑战第14天】shell代码训练(三)
12 1
|
6天前
|
存储 弹性计算 Shell
ecs服务器shell常用脚本练习(十)
【4月更文挑战第11天】shell代码训练(十)
136 0
|
6天前
|
弹性计算 Shell Go
ecs服务器shell常用脚本练习(九)
【4月更文挑战第10天】shell代码训练(八)
123 0
|
17天前
|
Shell
【shell】实时查看网卡流量脚本
【shell】实时查看网卡流量脚本
|
23天前
|
Shell Linux C++
【Shell 编程设计】 编写自己的清理后台的Shell脚本
【Shell 编程设计】 编写自己的清理后台的Shell脚本
29 1
|
28天前
|
Kubernetes Shell Docker
容器服务ACK常见问题之容器服务ACK kubectl命令写到shell脚本失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
29天前
|
Shell Linux 网络安全
性能工具之 JMeter 使用 shell 脚本快速执行
【2月更文挑战第30天】性能工具之 JMeter 使用 shell 脚本快速执行
93 1
性能工具之 JMeter 使用 shell 脚本快速执行