Bash Shell脚本实例

0 ——-

#!/bin/bash

#定位KILL命令
cmm="/usr/bin/kill"
if [ ! -f "$cmm" ]; then
    cmm="/bin/kill"
fi

#保持多少个进程
hold=2
if [ -n "$1" ]; then
    hold=$1
fi

#内存占用阈值(100M)
threshold=102400

#获取具体路径
pwd=$(cd `dirname $0`; pwd)

#搜索进程
search=$pwd'/artisan queue:work --queue=adc'

#循环杀掉超过阈值的进程
ps aux | grep $search | grep -v grep | awk '{print $2"|"$6}' | cat | while read line
do
    pid=`echo $line | cut -d "|" -f 1`
    rss=`echo $line | cut -d "|" -f 2`
    if [ $rss -gt $threshold ]; then
        kill=`$cmm -9 $pid`
        date=`date "+%Y-%m-%d %H:%M:%S"`
        echo $date' - 'PID:$pid' - RSS('$rss'K) > Threshold('$threshold'K) - Was Killed.'
    fi
done

#杀掉后维持进程数量
live=`ps -efH | grep $search | grep -v 'grep' | wc -l`
if [ $live -lt $hold ]; then
    for ((i=1; i<=$hold-$live; i=i+1))
    do
        php $search' --tries=3 --sleep=2 --timeout=300' 2>&1 >> /dev/null &
    done
fi

exit 0





#!/bin/bash

#定位KILL命令
cmm="/usr/bin/kill"
if [ ! -f "$cmm" ]; then
    cmm="/bin/kill"
fi

#操作系统位数
bit='32'
if [ $(getconf WORD_BIT) = '32' -a $(getconf LONG_BIT) = '64' ]; then
    bit='64'
fi

#端口
port=9515
if [ -n "$1" ]; then
    port=$1
fi

#获取具体路径
pwd=$(cd `dirname $0`; pwd)

#搜索进程
search=$pwd/chromedriver_linux$bit' --port='$port

#杀掉原来进程
ps aux | grep $search | grep -v grep | awk '{print $2}' | cat | while read pid
do
    kill=`$cmm -9 $pid`
    date=`date "+%Y-%m-%d %H:%M:%S"`
    echo $date' - 'PID:$pid' Was Killed.'
done

#重启进程
$pwd/chromedriver_linux$bit --port=$port 2>&1 >> /dev/null &

exit 0

##############################################################
##定时杀firefox

#!/bin/bash

#定位KILL命令
cmm="/usr/bin/kill"
if [ ! -f "$cmm" ]; then
    cmm="/bin/kill"
fi

#循环杀掉进程
ps aux | grep 'firefox/firefox' | grep -v grep | awk '{print $2"|"$6}' | cat | while read line
do
    pid=`echo $line | cut -d "|" -f 1`
    rss=`echo $line | cut -d "|" -f 2`

    kill=`$cmm -9 $pid`
    date=`date "+%Y-%m-%d %H:%M:%S"`
    echo $date' - 'PID:$pid' - RSS('$rss'K) Threshold('$threshold'K) - Firefox Was Killed.'
done

exit 0

1 内存监控,超过阀值则杀掉:

vi kill.sh

#!/bin/bash

#内存占用超过120M
threshold=120000
cmm="/usr/bin/kill"
if [ ! -f "$cmm" ]; then
    cmm="/bin/kill"
fi

ps aux | grep 'artisan queue:work' | grep -v grep | awk '{print $2"|"$6}' | cat | while read line
do
    pid=`echo $line | cut -d "|" -f 1`
    rss=`echo $line | cut -d "|" -f 2`

    if [ $rss -gt $threshold ]; then
        kill=`$cmm -9 $pid`
	date=`date "+%Y-%m-%d %H:%M:%S"`
        if [ $kill ]; then
            echo $date' -- 'PID:$pid' - RSS('$rss'K) > threshold('$threshold'K) - Was Killed.'
        elif
            ech $date' -- 'PID:$pid' - RSS('$rss'K) > threshold('$threshold'K) - Kill Failed.' 
        fi
    fi
done

这里被杀掉的进程由于有使用进程监控器监控,被杀掉后会自动重启。

2 内存监控,超过阀值则杀掉并重启

#!/bin/bash

#判断进程数量
live=`ps -efH | grep 'agent.js' | grep -v 'grep' | wc -l`
if [ $live -eq 0 ]; then
	/usr/local/bin/node /var/www/ebay-ap/agent.js 2>&1 >> /var/www/ebay-ap/log.txt &
fi

#判断是否超过阀值
threshold=204800

cmm="/usr/bin/kill"
if [ ! -f "$cmm" ]; then
    cmm="/bin/kill"
fi

ps aux | grep 'agent.js' | grep -v grep | awk '{print $2"|"$6}' | cat | while read line
do
    pid=`echo $line | cut -d "|" -f 1`
    rss=`echo $line | cut -d "|" -f 2`

    if [ $rss -gt $threshold ]; then
        date=`date "+%Y-%m-%d %H:%M:%S"`
        kill=`$cmm -9 $pid`
        if [ $kill ]; then
            echo $date -- PID: ${pid} Kill Failed [RSS: ${rss} gt ${threshold}]
        else
            echo $date -- PID: ${pid} Kill Success [RSS: ${rss} gt ${threshold}]
            /usr/local/bin/node /var/www/ebay-ap/agent.js 2>&1 >> /var/www/ebay-ap/log.txt &
        fi
    fi
done

如果进程异常退出了,则自动拉起。然后判断内存是否超标,如果超标则先杀掉然后再重启。这个方式看起来粗暴了一些,不过是非常有效的。

3 封杀某个区域的IP

#下载中国IP库
wget http://www.ipdeny.com/ipblocks/data/countries/cn.zone

#运行以下脚本
#!/bin/bash

COUNTRY = "cn"
IPTABLES = /sbin/iptables
EGREP = /bin/egrep

if [ "$(id -u)" != "0" ]; then
   echo "you must be root" 1>&2
   exit 1
fi

resetrules() {
    $IPTABLES -F
    $IPTABLES -t nat -F
    $IPTABLES -t mangle -F
    $IPTABLES -X
}

resetrules

for c in $COUNTRY
do
        country_file = $c.zone

        IPS = $($EGREP -v "^#|^$" $country_file)
        for ip in $IPS
        do
           echo "blocking $ip"
           $IPTABLES -A INPUT -s $ip -j DROP
        done
done

exit 0

4 防DD脚本

#!/bin/sh

IGNORE_IP_LIST="/usr/local/ddos/ignore.ip.list"
IPT="/sbin/iptables"

KILL=1

# NO_OF_CONNECTIONS默认是150,这是一个经验值,如果服务器性能比较高,可以设置200以上,以避免误杀
NO_OF_CONNECTIONS=150

# 解锁的时间,单位为秒,可以设置更长时间
BAN_PERIOD=86400

# 解除对IP的封锁 过程就是运行一个睡眠脚本
unbanip()
{
	# 产生解除IP封锁时用到的随机脚本文件
        UNBAN_SCRIPT=`mktemp /tmp/unban.XXXXXXXX`

	# 临时文件
        TMP_FILE=`mktemp /tmp/unban.XXXXXXXX`

	# 将被解除封锁的IP
        UNBAN_IP_LIST=`mktemp /tmp/unban.XXXXXXXX`

	# 产生解除IP封锁的脚本内容
        echo '#!/bin/sh' > $UNBAN_SCRIPT
	# $BAN_PERIOD睡眠时间,表示$UNBAN_SCRIPT睡眠多久后继续
        echo "sleep $BAN_PERIOD" >> $UNBAN_SCRIPT

	# 输入重定向,行对于$line变量,是当前需要堵塞的IP,脚本运行过程中产生
	while read line; do
		# 解除IP封锁
		echo "$IPT -D INPUT -s $line -j DROP" >> $UNBAN_SCRIPT

		# 把将要解除堵塞的IP写入$UNBAN_IP_LIST
		echo $line >> $UNBAN_IP_LIST
	done < $BANNED_IP_LIST

        # 从$IGNORE_IP_LIST中去掉$UNBAN_IP_LIST,把结果写入$TMP_FILE(差集)
        echo "grep -v --file=$UNBAN_IP_LIST $IGNORE_IP_LIST > $TMP_FILE" >> $UNBAN_SCRIPT

	# 移动$TMP_FILE到$IGNORE_IP_LIST
        echo "mv $TMP_FILE $IGNORE_IP_LIST" >> $UNBAN_SCRIPT

	# 删除$UNBAN_SCRIPT
        echo "rm -f $UNBAN_SCRIPT" >> $UNBAN_SCRIPT
	# 删除$UNBAN_IP_LIST
        echo "rm -f $UNBAN_IP_LIST" >> $UNBAN_SCRIPT
	# 删除$TMP_FILE,经过上面的移动操作,$TMP_FILE其实已经不存在
        echo "rm -f $TMP_FILE" >> $UNBAN_SCRIPT

	# 在后台运行$UNBAN_SCRIPT
	. $UNBAN_SCRIPT &
}


TMP_PREFIX='/tmp/ddos'
TMP_FILE="mktemp $TMP_PREFIX.XXXXXXXX"

# 产生临时文件,存放已经被堵塞的IP
BANNED_IP_LIST=`$TMP_FILE`

# 产生临时文件,存放当前可能被堵塞的IP
BAD_IP_LIST=`$TMP_FILE`

#取回IP列表并按照数量从高到底排序
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr > $BAD_IP_LIST

# 如果配置为需要堵塞
if [ $KILL -eq 1 ]; then            
	# 超过100就记录
	NUM_CONNECTIONS=100  
	# 按照日期存放
	CNTS_LOG="/usr/local/ddos/$(date +%Y)/$(date +%m)/"
	mkdir -p $CNTS_LOG
	CNTS_LOG="$CNTS_LOG$(date +%Y%m%d).log"
	while read line; do
		CURR_CONN=$(echo $line | cut -d" " -f1)
		CURR_IP=$(echo $line | cut -d" " -f2)
		if [ $CURR_CONN -lt $NUM_CONNECTIONS ]; then
			break
		fi
		echo "$CURR_IP with $CURR_CONN connections at `date`" >> $CNTS_LOG
	done < $BAD_IP_LIST

        IP_BAN_NOW=0
        while read line; do
		# 当前这个IP有多少个连接
                CURR_LINE_CONN=$(echo $line | cut -d" " -f1)            
		# 当前IP
                CURR_LINE_IP=$(echo $line | cut -d" " -f2)          

		# 如果这个IP链接数小于预设,终止(因为数据经过排序)
                if [ $CURR_LINE_CONN -lt $NO_OF_CONNECTIONS ]; then     
			break
                fi

		# 计算当前IP在$IGNORE_IP_LIST出现了多少次
                IGNORE_BAN=`grep -c $CURR_LINE_IP $IGNORE_IP_LIST`
		# 如果当前IP已经在$IGNORE_IP_LIST,跳过,可以通过这个方式设置永不堵塞某些IP
                if [ $IGNORE_BAN -ge 1 ]; then
			continue
                fi

		# 进入到这里表示当前必定有IP要被堵塞
                IP_BAN_NOW=1

		# 添加堵塞了的IP到当前堵塞列表,$BANNED_IP_LIST会应用到unbanip函数
                # 如果不实现自动解锁,注释如下行
                echo $CURR_LINE_IP >> $BANNED_IP_LIST

		# 添加堵塞了的IP到$IGNORE_IP_LIST
                # 如果不实现自动解锁,注释如下行
                echo $CURR_LINE_IP >> $IGNORE_IP_LIST
                
		# 开始iptables封锁
                $IPT -I INPUT -s $CURR_LINE_IP -j DROP
                
        done < $BAD_IP_LIST

	# $IP_BAN_NOW等于1表示有IP被封锁了
        if [ $IP_BAN_NOW -eq 1 ]; then
		# 发送通知

		# 同时开始运行解除堵塞程序
                #unbanip                             
        fi
fi

# 清除临时产生的文件
rm -f $TMP_PREFIX.*

函数unbanip实际就是运行一个睡眠脚本,可以把其去掉(不自动解封):

#!/bin/sh

IGNORE_IP_LIST="/usr/local/ddos/ignore.ip.list"
IPT="/sbin/iptables"
KILL=1
NO_OF_CONNECTIONS=150

TMP_PREFIX='/tmp/ddos'
TMP_FILE="mktemp $TMP_PREFIX.XXXXXXXX"


BAD_IP_LIST=`$TMP_FILE`
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr > $BAD_IP_LIST

if [ $KILL -eq 1 ]; then
        IP_BAN_NOW=0
        while read line; do
		# 当前这个IP有多少个连接
                CURR_LINE_CONN=$(echo $line | cut -d" " -f1)            
		# 当前IP
                CURR_LINE_IP=$(echo $line | cut -d" " -f2)          

		# 如果这个IP链接数小于预设,终止(因为数据经过排序)
                if [ $CURR_LINE_CONN -lt $NO_OF_CONNECTIONS ]; then     
			break
                fi

		# 计算当前IP在$IGNORE_IP_LIST出现了多少次
                IGNORE_BAN=`grep -c $CURR_LINE_IP $IGNORE_IP_LIST`
		# 如果当前IP已经在$IGNORE_IP_LIST,跳过,可以通过这个方式设置永不堵塞某些IP
                if [ $IGNORE_BAN -ge 1 ]; then
			continue
                fi

		# 进入到这里表示当前必定有IP要被堵塞
                IP_BAN_NOW=1
                
		# 开始iptables封锁
                $IPT -I INPUT -s $CURR_LINE_IP -j DROP
        done < $BAD_IP_LIST

	# $IP_BAN_NOW等于1表示有IP被封锁了
        if [ $IP_BAN_NOW -eq 1 ]; then
		# 发送通知 CURL                           
        fi
fi

# 清除临时产生的文件
rm -f $TMP_PREFIX.*

如果仅仅希望监控一下哪些IP链接数过多,则可以如下改造:

#!/bin/sh

CNTS_LOG="/root/dd/log.txt"
IGNORE_IP_LIST="/root/dd/ignore.ip.list"
CONNECTIONS=5
 
TMP_PREFIX='/tmp/dd'
TMP_FILE="mktemp $TMP_PREFIX.XXXXXXXX"

BAD_IP_LIST=`$TMP_FILE`
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr > $BAD_IP_LIST

while read line; do
    CURR_CONN=$(echo $line | cut -d" " -f1)
    CURR_IP=$(echo $line | cut -d" " -f2)
    if [ $CURR_CONN -lt $CONNECTIONS ]; then
        break
    fi

    IGNORE=`grep -c $CURR_LINE_IP $IGNORE_IP_LIST`
    if [ $IGNORE -ge 1 ]; then
        continue
    fi

    echo "`date "+%Y-%m-%d %H:%M:%S"`|$CURR_IP|$CURR_CONN" >> $CNTS_LOG
done < $BAD_IP_LIST
 
rm -f $TMP_PREFIX.*