Linux运维常用shell脚本实例(4)

目录

1、统计和分析Apache日志

2、屏蔽每分钟访问超过200的IP

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

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

5、监控LINUX目录和文件变化

6、查看网卡实时流量

7、Nginx启动脚本

8、检查网站可用性

9.统计当前目录中以.html结尾的文件总大小

10.crontab操作

11、contab操作案例

12、contab操作案例

13、批量权限控制脚本


1、统计和分析Apache日志

     通过apache访问日志access.log 统计IP和每个地址访问的次数,按访问量列出前10名。
     日志格式样例如下:
     192.168.1.247  ---【02/jul/2010:23:44:59 + 8080 】 "GET /HTTP/1/1"   200 19
     答案:
         cat  access.log | awk '{print  $1}' |sort| uniq -c |sort -rn |head -10
 (uniq 参数说明:– c 显示输出中,在每行行首加上本行在文件中连续出现的次数。
     sort参数说明:sort默认的排序方式是升序,-r 参数就会改变成倒叙;你有没有遇到过10比2小的情况。我反正遇到过。出现这种情况是由于排序程序将这些数字按字符来排序了,排序程序会先比较1和2,显然1小,所以就将10放在2前面喽。这也是sort的一贯作风。)

2、屏蔽每分钟访问超过200的IP

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

 
  1. #!/bin/bash

  2. DATE=$(date +%d/%b/%Y:%H:%M)

  3. ABNORMAL_IP=$(tail -n5000 access.log |grep $DATE |awk '{a[$1]++}END{for(i in a)if(a[i]>100)print i}')

  4. #先tail防止文件过大,读取慢,数字可调整每分钟最大的访问量。awk不能直接过滤日志,因为包含特殊字符。

  5. for IP in $ABNORMAL_IP; do

  6.     if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then

  7.         iptables -I INPUT -s $IP -j DROP

  8.     fi

  9. done

方法2:通过建立连接数

 
  1. 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}')

  2. #gsub是将第五列(客户端IP)的冒号和端口去掉

  3. for IP in $ABNORMAL_IP; do

  4.     if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then

  5.         iptables -I INPUT -s $IP -j DROP

  6.     fi

  7. done

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

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

 
  1. DATE=$(date +"%a %b %e %H:%M") #星期月天时分  %e单数字时显示7,而%d显示07

  2. ABNORMAL_IP=$(lastb |grep "$DATE" |awk '{a[$3]++}END{for(i in a)if(a[i]>10)print i}')

  3. for IP in $ABNORMAL_IP; do

  4.     if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then

  5.         iptables -I INPUT -s $IP -j DROP

  6.     fi

  7. done

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

 
  1. DATE=$(date +"%b %d %H")

  2. 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}')"

  3. for IP in $ABNORMAL_IP; do

  4.     if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then

  5.         iptables -A INPUT -s $IP -j DROP

  6.         echo "$(date +"%F %T") - iptables -A INPUT -s $IP -j DROP" >>~/ssh-login-limit.log

  7.     fi

  8. done

 

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

需安装inotify-tools软件包。

 
  1. #!/bin/bash

  2. MON_DIR=/opt

  3. inotifywait -mq --format %f -e create $MON_DIR |\

  4. while read files; do

  5.   echo $files >> test.log

  6. done

  7. 12.16 多个网卡选择

  8. function local_nic() {

  9.     local NUM ARRAY_LENGTH

  10.     NUM=0

  11.     for NIC_NAME in $(ls /sys/class/net|grep -vE "lo|docker0"); do

  12.         NIC_IP=$(ifconfig $NIC_NAME |awk -F'[: ]+' '/inet addr/{print $4}')

  13.         if [ -n "$NIC_IP" ]; then

  14.             NIC_IP_ARRAY[$NUM]="$NIC_NAME:$NIC_IP"    #将网卡名和对应IP放到数组

  15.             let NUM++

  16.         fi

  17.     done

  18.     ARRAY_LENGTH=${#NIC_IP_ARRAY[*]}

  19.     if [ $ARRAY_LENGTH -eq 1 ]; then     #如果数组里面只有一条记录说明就一个网卡

  20.         NIC=${NIC_IP_ARRAY[0]%:*}

  21.         return 0

  22.     elif [ $ARRAY_LENGTH -eq 0 ]; then   #如果没有记录说明没有网卡

  23.         echo "No available network card!"

  24.         exit 1

  25.     else

  26.         #如果有多条记录则提醒输入选择

  27.         for NIC in ${NIC_IP_ARRAY[*]}; do

  28.             echo $NIC

  29.         done

  30.         while true; do

  31.             read -p "Please enter local use to network card name: " INPUT_NIC_NAME

  32.             COUNT=0

  33.             for NIC in ${NIC_IP_ARRAY[*]}; do

  34.                 NIC_NAME=${NIC%:*}

  35.                 if [ $NIC_NAME == "$INPUT_NIC_NAME" ]; then

  36.                     NIC=${NIC_IP_ARRAY[$COUNT]%:*}

  37.                     return 0

  38.                 else

  39.                    COUNT+=1

  40.                 fi

  41.             done

  42.             echo "Not match! Please input again."

  43.         done

  44.     fi

  45. }

  46. local_nic

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

5、监控LINUX目录和文件变化

利用一个脚本能够实时监控web目录下文件的变化,也就是对该目录的增删改操作都会记录到相应日志下。

主要有两个脚本:

脚本1:将需要监控的目录的原始状态保存到LOG日志
脚本2:将脚本1的原始状态与本脚本比对,如果目录文件发生变化,则将变化的内容保存到日志。

1,监控 /home/www/ 目录改动,并将改动的文件rsync到/home/www3目录

2,监控方法为监控文件的md5值,如果md5值与上次不同,即发生改变

注:原理实际上利用的是du -sb输出值来判断文件的变化,再利用diff进行比对。

1.在执行脚本前要保存原始的状态:

# vi initial.sh

 
  1. #!/bin/bash

  2. PATH=/bin:/sbin:/usr/bin:/usr/sbin/:/usr/local/bin:/usr/local/sbin:~/bin

  3. export PATH

  4. # 监控的目录

  5. DIR=/root

  6. # 临时文件

  7. TMP_A=/tmp/a.txt

  8. # 遍历指定目录下的文件大小及路径并重定向到日志文件

  9. find $DIR -print0 | xargs -0 du -sb > $TMP_A

2.执行监控脚本
# vi monitor.sh

 
  1. #!/bin/bash

  2. PATH=/bin:/sbin:/usr/bin:/usr/sbin/:/usr/local/bin:/usr/local/sbin:~/bin

  3. export PATH

  4. # 监控的目录

  5. DIR=/root

  6. # 日期变量

  7. DATE=`date +%F_%H:%M`

  8. # 临时文件

  9. TMP_A=/tmp/a.txt

  10. TMP_B=/tmp/b.txt

  11. TMP_C=/tmp/c.txt

  12. # 日志文件

  13. LOG=/var/log/filemodify.log

  14. # 遍历指定目录下的文件大小及路径并重定向到日志文件

  15. find $DIR -print0 | xargs -0 du -sb > $TMP_B

  16. # 比较目录变化,并将变化的文件写入日志

  17. DIFF=$(diff $TMP_A $TMP_B)

  18. if [[ -z $DIFF ]];

  19. then

  20. echo "Nothing change" >> $LOG

  21. else

  22. echo "Here is the change" >> $LOG

  23. echo "" >> $LOG

  24. echo "$DIFF" |awk '{print $3}'|sort -k2n |uniq |sed '/^$/d' |tee $TMP_C >> $LOG

  25. if [ -s $TMP_C ];

  26. then

  27. echo "" >> $LOG

  28. echo "It modified at $DATE" >> $LOG

  29. # 将当前监控的目录结构覆盖为初始状态

  30. find $DIR -print0 | xargs -0 du -sb > $TMP_A

  31. fi

  32. fi

  33. echo "====================================" >> $LOG

  34. #清理临时文件

  35. rm -rf $TMP_B $TMP_C

Shell脚本监控目录内文件改动

 
  1. #! /bin/bash

  2. webroot="/home/www/"

  3. cp /dev/null rsync_file

  4. if [ ! -f file.md5 ];then

  5. find $webroot -type f -exec md5sum {} \; >>file.md5

  6. else

  7. for file in $(md5sum -c file.md5|awk -F':' '/FAILED/{print $1}')

  8. do

  9. if [ -f $file ];then

  10. filename_z=$(echo $file|sed 's#/#\\/#g')

  11. sed -i "/ $filename_z/"d file.md5

  12. md5sum $file >> file.md5

  13. echo $file >> rsync_file

  14. else

  15. echo $file >>rsync_rm

  16. fi

  17. done

  18. for newfile in $(find $webroot -type f)

  19. do

  20. grep $newfile file.md5 >/dev/null 2>&1

  21. if [ $? -gt 0 ];then

  22. md5sum $newfile >> file.md5

  23. echo "$newfile" >> rsync_file

  24. fi

  25. done

  26. for rfile in $(cat rsync_file)

  27. do

  28. rsync -avzp $rfile /home/www3/

  29. done

6、查看网卡实时流量

 
  1. #!/bin/bash

  2. # Description: Only CentOS6

  3. traffic_unit_conv() {

  4.     local traffic=$1

  5.     if [ $traffic -gt 1024000 ]; then

  6.         printf "%.1f%s" "$(($traffic/1024/1024))" "MB/s"

  7.     elif [ $traffic -lt 1024000 ]; then

  8.         printf "%.1f%s" "$(($traffic/1024))" "KB/s"

  9.     fi

  10. }

  11. NIC=$1

  12. echo -e " In ------ Out"

  13. while true; do

  14.     OLD_IN=$(awk -F'[: ]+' '$0~"'$NIC'"{print $3}' /proc/net/dev)

  15.     OLD_OUT=$(awk -F'[: ]+' '$0~"'$NIC'"{print $11}' /proc/net/dev)

  16.     sleep 1

  17.     NEW_IN=$(awk -F'[: ]+' '$0~"'$NIC'"{print $3}' /proc/net/dev)

  18.     NEW_OUT=$(awk -F'[: ]+' '$0~"'$NIC'"{print $11}' /proc/net/dev)

  19.     IN=$(($NEW_IN-$OLD_IN))

  20.     OUT=$(($NEW_OUT-$OLD_OUT))

  21.     echo "$(traffic_unit_conv $IN) $(traffic_unit_conv $OUT)"

  22.     sleep 1

  23. done

  24. # 也可以通过ficonfig命令获取收发流量

  25. while true; do

  26.     OLD_IN=$(ifconfig $NIC |awk -F'[: ]+' '/bytes/{print $4}')  

  27.     OLD_OUT=$(ifconfig $NIC |awk -F'[: ]+' '/bytes/{print $9}')

  28.     sleep 1

  29.     NEW_IN=$(ifconfig $NIC |awk -F'[: ]+' '/bytes/{print $4}')

  30.     NEW_OUT=$(ifconfig $NIC |awk -F'[: ]+' '/bytes/{print $9}')

  31.     IN=$(($NEW_IN-$OLD_IN))

  32.     OUT=$(($NEW_OUT-$OLD_OUT))

  33.     echo "$(traffic_unit_conv $IN) $(traffic_unit_conv $OUT)"

  34.     sleep 1

  35. done

7、Nginx启动脚本

 
  1. #!/bin/bash

  2. # Description: Only support RedHat system

  3. . /etc/init.d/functions

  4. WORD_DIR=/data/project/nginx1.10

  5. DAEMON=$WORD_DIR/sbin/nginx

  6. CONF=$WORD_DIR/conf/nginx.conf

  7. NAME=nginx

  8. PID=$(awk -F'[; ]+' '/^[^#]/{if($0~/pid;/)print $2}' $CONF)

  9. if [ -z "$PID" ]; then

  10.     PID=$WORD_DIR/logs/nginx.pid

  11. else

  12.     PID=$WORD_DIR/$PID

  13. fi

  14. stop() {

  15.     $DAEMON -s stop

  16.     sleep 1

  17.     [ ! -f $PID ] && action "* Stopping $NAME"  /bin/true || action "* Stopping $NAME" /bin/false

  18. }

  19. start() {

  20.     $DAEMON

  21.     sleep 1

  22.     [ -f $PID ] && action "* Starting $NAME"  /bin/true || action "* Starting $NAME" /bin/false

  23. }

  24. reload() {

  25.     $DAEMON -s reload

  26. }

  27. test_config() {

  28.     $DAEMON -t

  29. }

  30. case "$1" in

  31.     start)

  32.         if [ ! -f $PID ]; then

  33.             start

  34.         else

  35.             echo "$NAME is running..."

  36.             exit 0

  37.         fi

  38.         ;;

  39.     stop)

  40.         if [ -f $PID ]; then

  41.             stop

  42.         else

  43.             echo "$NAME not running!"

  44.             exit 0

  45.         fi

  46.         ;;

  47.     restart)

  48.         if [ ! -f $PID ]; then

  49.             echo "$NAME not running!" 

  50.             start

  51.         else

  52.             stop

  53.             start

  54.         fi

  55.         ;;

  56.     reload)

  57.         reload

  58.         ;;

  59.     testconfig)

  60.         test_config

  61.         ;; 

  62.     status)

  63.         [ -f $PID ] && echo "$NAME is running..." || echo "$NAME not running!"

  64.         ;;

  65.     *)

  66.         echo "Usage: $0 {start|stop|restart|reload|testconfig|status}"

  67.         exit 3

  68.         ;;

  69. esac

8、检查网站可用性

1)检查URL可用性

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

方法1:

check_url() {

    HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $1)

    if [ $HTTP_CODE -ne 200 ]; then

        echo "Warning: $1 Access failure!"

    fi

}

方法2:

check_url() {

if ! wget -T 10 --tries=1 --spider $1 >/dev/null 2>&1; then  

#-T超时时间,--tries尝试1次,--spider爬虫模式

        echo "Warning: $1 Access failure!"

    fi

}

使用方法:check_url www.baidu.com

2)判断三次URL可用性

思路与上面检查主机存活状态一样。

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

方法1:利用循环技巧,如果成功就跳出当前循环,否则执行到最后一行

#!/bin/bash  

check_url() {

    HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $1)

    if [ $HTTP_CODE -eq 200 ]; then

        continue

    fi

}

URL_LIST="www.baidu.com www.agasgf.com"

for URL in $URL_LIST; do

    check_url $URL

    check_url $URL

    check_url $URL

    echo "Warning: $URL Access failure!"

done

方法2:错误次数保存到变量

#!/bin/bash  

URL_LIST="www.baidu.com www.agasgf.com"

for URL in $URL_LIST; do

    FAIL_COUNT=0

    for ((i=1;i<=3;i++)); do

        HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $URL)

        if [ $HTTP_CODE -ne 200 ]; then

            let FAIL_COUNT++

        else

            break

        fi

    done

    if [ $FAIL_COUNT -eq 3 ]; then

        echo "Warning: $URL Access failure!"

    fi

done

方法3:错误次数保存到数组

#!/bin/bash  

URL_LIST="www.baidu.com www.agasgf.com"

for URL in $URL_LIST; do

    NUM=1

    while [ $NUM -le 3 ]; do

        HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $URL)

        if [ $HTTP_CODE -ne 200 ]; then

            FAIL_COUNT[$NUM]=$IP  #创建数组,以$NUM下标,$IP元素

            let NUM++

        else

            break

        fi

    done

    if [ ${#FAIL_COUNT[*]} -eq 3 ]; then

        echo "Warning: $URL Access failure!"

        unset FAIL_COUNT[*]    #清空数组

    fi

done

9.统计当前目录中以.html结尾的文件总大小

1

2

3

4

5

6

7

8

9

方法1:

# find . -name "*.html" -maxdepth 1 -exec du -b {} \; |awk '{sum+=$1}END{print sum}'

方法2:

for size in $(ls -l *.html |awk '{print $5}'); do

    sum=$(($sum+$size))

done

echo $sum

递归统计:

# find . -name "*.html" -exec du -k {} \; |awk '{sum+=$1}END{print sum}'

10.crontab操作

某系统管理员需要每天做一定的重复工作,编制一个解决方案:
(1).从下午4:50 删除/abc 目录下的全部子目录和全部文件;
(2).从早上8:00~下午6:00 每小时读取/xyz 目录下x1 文件中每行第一个域的全部数
据加入到/backup 目录下的back01.txt 文件内;
(3).每逢周一下午5:50 将/data 目录下的所有目录和文件归档并压缩为文件
backup.tar.gz;
(4).在下午5:55 将IDE 接口的CD-ROM 缷载(假设CD-ROM 的设备名为hdc);
(5).在早上8:00 前开机后启动。
(a)用vi创建编辑一个名为prgx的crontab文件;
(b)prgx文件的内容:
            50 16 * * * rm -r /abc/*
            0 8-18/1 * * * cut -f1 /xyz/x1 >>  /backup/bak01.txt
            50 17 * * * tar zcvf backup.tar.gz /data
            55 17 * * * umount /dev/hdc
(c)由超级用户登录,用crontab执行 prgx文件中的内容:
            root@xxx:#crontab prgx;在每日早晨8:00之前开机后即可自动启动crontab

11、contab操作案例

在每月第一天备份并压缩/etc目录的所有内容,存放在/root/bak目录里,且文件名为如下形式yymmdd_etc,yy为年,mm为月,dd为日。Shell程序fileback存放在/usr/bin目录下。 
(1)编写shell程序fileback: 

#!/bin/sh 
DIRNAME=`ls /root | grep bak` 
if [ -z "$DIRNAME" ] ; then 
mkdir /root/bak 
cd /root/bak 
fi
BACKETC=$(date +%Y%m%d)_etc.tar.gz 
tar zcvf  $BACKETC  /etc 
echo "fileback finished!" 

(2)编写任务定时器: 
echo "0 0 1 * * /bin/sh /usr/bin/fileback" >; /root/etcbakcron 
crontab /root/etcbakcron 
或使用crontab -e 命令添加定时任务: 
0 1 * * * /bin/sh /usr/bin/fileback 

12、contab操作案例

有一普通用户想在每周日凌晨零点零分定期备份/user/backup到/tmp目录下,该用户应如何做? 
(1)第一种方法: 
用户应使用crontab –e 命令创建crontab文件。格式如下: 
0 0 * * sun cp –r /user/backup /tmp 
(2)第二种方法: 
用户先在自己目录下新建文件file,文件内容如下: 
0 * * sun cp –r /user/backup /tmp 
然后执行 crontab file 使生效。 

13、批量权限控制脚本

设计一个Shell程序,在/userdata目录下建立50个目录,即user1~user50,并设置每个目录的权限,其中其他用户的权限为:读;文件所有者的权限为:读、写、执行;文件所有者所在组的权限为:读、执行。 
如下: 

#!/bin/sh 
i=1 
while [ i -le 50 ] 
do 
	if [ -d /userdata ];then 
		mkdir -p -m 754 /userdata/user$i   加上-m 754 就不用写下面那一句了  -p 是递归建立目录 
		#chmod 754 /userdata/user$i 
		echo "user$i" 
		let "i = i + 1" (或i=$(($i+1)) 
	else 
		mkdir /userdata 
		mkdir -p -m /userdata/user$i 
		#chmod 754 /userdata/user$i 
		echo "user$i" 
		let "i = i + 1" (或i=$(($i+1)) 
	fi 
done

 

你可能感兴趣的:(Shell)