Linux 常用Shell脚本

words: 2.1k    views:    time: 11min

常用的shell脚本整理

系统信息

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
## 操作系统
if [ -f "/etc/os-release" ]; then
. /etc/os-release
os_name="$PRETTY_NAME"
elif [ -f "/etc/redhat-release" ]; then
os_name=$(cat /etc/redhat-release)
else
os_name=$(uname -s)
fi

## 硬件架构
arch=$(uname -m)

## 主机名称
host_name=$(hostname -f 2>/dev/null || hostname || uname -n)

## 启动时间
up_time=$(uptime -s)

## cpu型号
cpu_mode=$(LANG=C lscpu | awk -F: '/Model name/ {print $2}' | awk '$1=$1')

## cpu核数
cpu_core=$(awk '/processor/{core++} END {print core}' /proc/cpuinfo)

## cpu使用率
cpu_usage=$(top -b -n 1 | awk '/%Cpu/ {print $2 + $4; exit}')

## 内存使用
free -k | grep -iv swap | awk -F ':' '{print $NF}' | \
awk -F ' ' '{
for(i=1;i<=NF;i++) a[i,NR]=$i
} END {
for(i=1;i<=NF;i++) {
printf "mem "
for(j=1;j<=NR;j++) {
printf a[i,j]
if (j < NR) printf ":"
}
print ""
}
}'

## 磁盘使用
df -k | awk 'NR>1' | awk '/^\/dev\// {print $1 " " $2 " " $3 " " $5 " " $6}'

系统设置

1
2
3
4
5
6
7
8
9
10
11
12
13
## 系统参数
cat >> /etc/sysctl.conf << EOF
## 网卡接收队列的最大长度,默认1000,调高可以应对突发大流量,防止丢包,比如当内核处理速度慢于网卡接收速度时
net.core.netdev_max_backlog = 262144
## SYN半连接队列的最大长度(尚未完成三次握手的连接请求队列),默认1024,调高一点防止丢包
net.ipv4.tcp_max_syn_backlog = 20480
## 启用SYN Cookie防护,防止SYN Flood攻击,当半连接队列满时,不丢弃连接,而是通过Cookie机制验证
net.ipv4.tcp_syncookies = 1
## 保持TIME_WAIT状态的最大socket数量,默认180000,防止TIME_WAIT耗尽内存,但太低会影响连接复用
net.ipv4.tcp_max_tw_buckets = 20480
## FIN_WAIT_2连接关闭等待的最后阶段,默认60,调低一点可以快速释放无效连接,节省资源
net.ipv4.tcp_fin_timeout = 20
EOF

目录文件

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
## 备份目录,将source_dir目录下的所有文件打包压缩,保存到backup_dir
tar -zcvf "$backup_dir/back_$(date +"%Y%m%d%H%M%S").tar.gz" -C "$source_dir" .

## 统计目录中.log文件的大小
find . -name "*.log" -exec du -k {} \; |awk '{sum+=$1}END{print sum}'  

## 定时清理文件(删除7天前的文件)
TEMP_DIR="/path/to/temp"
DAYS_OLD=7
find $TEMP_DIR -type f -mtime +$DAYS_OLD -exec rm -f {} \;

## 文件内容监控
KEYWORD="ERROR"
LOG_FILE="/var/log/syslog"
EMAIL="your_email@example.com"

tail -Fn0 "$LOG_FILE" | while read line; do
if [[ "$line" == *"$KEYWORD"* ]]; then
echo "$line" | mail -s "Error found in log file" "$EMAIL"
fi
done

## 文本数字统计,按行统计再汇总
## 文件总行数
n=`wc -l a.txt|awk '{print $1}'`
sum=0
for i in `seq 1 $n`
do
## 获取第i行的内容
line=`sed -n "$i"p a.txt`
## 行数字统计
n_n=`echo $line|sed s'/[^0-9]//'g|wc -L`
echo $n_n
sum=$[$sum+$n_n]
done
echo "sum:$sum"

## 监控100台服务器磁盘使用率
HOST_INFO=host.info
for IP in $(awk '/^[^#]/{print $1}' $HOST_INFO); do
    USER=$(awk -v ip=$IP 'ip==$1{print $2}' $HOST_INFO)
    PORT=$(awk -v ip=$IP 'ip==$1{print $3}' $HOST_INFO)
    TMP_FILE=/tmp/disk.tmp
    ssh -p $PORT $USER@$IP 'df -h' > $TMP_FILE
    USE_RATE_LIST=$(awk 'BEGIN{OFS="="}/^\/dev/{print $NF,int($5)}' $TMP_FILE)
    for USE_RATE in $USE_RATE_LIST; do
        PART_NAME=${USE_RATE%=*}
        USE_RATE=${USE_RATE#*=}
        if [ $USE_RATE -ge 80 ]; then
            echo "Warning: $PART_NAME Partition usage $USE_RATE%!"
        fi
    done
done

## 比较两台服务器指定目录下的文件一致性(以本地为参考,比较md5)
dir=/data/web
b_ip=192.168.88.10

find $dir -type f|xargs md5sum > /tmp/md5_a.txt
ssh $b_ip "find $dir -type f|xargs md5sum > /tmp/md5_b.txt"
scp $b_ip:/tmp/md5_b.txt /tmp
for f in `awk '{print 2} /tmp/md5_a.txt'`
do
if grep -qw "$f" /tmp/md5_b.txt
then
md5_a=`grep -w "$f" /tmp/md5_a.txt|awk '{print 1}'`
md5_b=`grep -w "$f" /tmp/md5_b.txt|awk '{print 1}'`
if [ $md5_a != $md5_b ]
then
echo "$f changed."
fi
else
echo "$f deleted."
fi
done

## ftp上传
FTP_SERVER="192.168.1.100"
FTP_USER="your_username"
FTP_PASS="your_password"
LOCAL_FILE="/path/to/local/file"
REMOTE_DIR="/path/to/remote/dir"

ftp -inv $FTP_SERVER <<EOF
user $FTP_USER $FTP_PASS
cd $REMOTE_DIR
put $LOCAL_FILE
bye
EOF

## ftp下载
ftp -n -v << EOF
open $FTP_SERVER
user $FTP_USER $FTP_PASS
binary
cd $dir
get "$file"
EOF

网络检测

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
## 检查网络连接
HOST="8.8.8.8"
INTERVAL=10
LOG_FILE="/var/log/network_status.log"

while true; do
  DATE=$(date +"%Y-%m-%d %H:%M:%S")
if ping -c 1 $HOST &> /dev/null; then
    echo"$DATE Network is up" >> $LOG_FILE
else
    echo"$DATE Network is down" >> $LOG_FILE
fi
  sleep $INTERVAL
done

## 查看网卡实时流量
NIC=eth0
echo -e " In ------ Out"
while true; do
    OLD_IN=$(awk '$0~"'$NIC'" {print $2}' /proc/net/dev)
    OLD_OUT=$(awk '$0~"'$NIC'" {print $10}' /proc/net/dev)
    sleep 1
    NEW_IN=$(awk '$0~"'$NIC'" {print $2}' /proc/net/dev)
    NEW_OUT=$(awk '$0~"'$NIC'" {print $10}' /proc/net/dev)
    IN=$(printf "%.1f%s" "$((($NEW_IN-$OLD_IN)/1024))" "KB/s")
    OUT=$(printf "%.1f%s" "$((($NEW_OUT-$OLD_OUT)/1024))" "KB/s")
    echo "$IN $OUT"
    sleep 1
done

## 扫描服务端口
HOST=$1
PORT="22 25 80 8080"
for PORT in $PORT; do
if echo &>/dev/null > /dev/tcp/$HOST/$PORT; then
echo "$PORT open"
else
echo "$PORT close"
fi
done

## 查找较多TIME_WAIT连接
netstat -n|grep TIME_WAIT|awk '{print $5}'|sort|uniq -c|sort -rn|head -n20

## 每个ip的连接数,以及总的各个状态的连接数
netstat -n | awk '/^tcp/ {n=split($(NF-1),array,":");if(n<=2)++S[array[(1)]];else++S[array[(4)]];++s[$NF];++N} END {for(a in S){printf("%-20s %s\n", a, S[a]);++I}printf("%-20s %s\n","TOTAL_IP",I);for(a in s) printf("%-20s %s\n",a, s[a]);printf("%-20s %s\n","TOTAL_LINK",N);}'

## 抓取1000个发往80端口的IP包,统计每个源IP的出现次数,显示前20个最活跃的IP
tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." '{print $1"."$2"."$3"."$4}' | sort | uniq -c | sort -nr | head -20

## 屏蔽异常访问的ip(每分钟访问80端口超过100次)
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}')#
for IP in $ABNORMAL_IP; do
if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
iptables -I INPUT -s $IP -j DROP
    fi
done

## 屏蔽SSH异常的ip(每分钟登录失败超过10次)
DATE=$(date +"%a %b %e %H:%M")
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

## 根据访问日志,封禁请求量异常的IP,每半小时尝试恢复
logfile=/data/log/access.log
d1=`date -d "-1 minute" +%H%M`
d2=`date +%M`
ipt=/sbin/iptables
ips=/tmp/ips.txt

block()
{
## 将一分钟前的日志全部过滤出来并提取IP以及统计访问次数
grep '$d1:' $logfile|awk '{print $1}'|sort -n|uniq -c|sort -n > $ips
## 将次数超过100的IP遍历出来并封禁
for i in `awk '$1>100 {print $2}' $ips`
do
$ipt -I INPUT -p tcp --dport 80 -s $i -j REJECT
done
}

unblock()
{
## pkts数量小于10的IP
for a in `$ipt -nvL INPUT --line-numbers |grep '0.0.0.0/0'|awk '$2<10 {print $1}'|sort -nr`
do
$ipt -D INPUT $a
done
$ipt -Z
}

if [ $d2 -eq "00" ] || [ $d2 -eq "30" ];then
unblock
block
else
block
fi

日志分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
## Nginx日志分析
## 日志格式: $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"

## 查看有多少个IP访问
awk '{print $1}' $LOG_FILE|sort|uniq|wc -l

## 统计访问最多的10个IP
awk '{a[$1]++}END{print "UV:",length(a);for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr |head -10

## 统计时间段访问最多的IP
awk '$4>="[01/Dec/2018:13:20:25" && $4<="[27/Nov/2018:16:20:49"{a[$1]++}END{for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr|head -10

## 统计访问最多的10个页面
awk '{a[$7]++}END{print "PV:",length(a);for(v in a){if(a[v]>10)print v,a[v]}}' $LOG_FILE |sort -k2 -nr

## 统计访问页面状态码数量
awk '{a[$7" "$9]++}END{for(v in a){if(a[v]>5)print v,a[v]}}'

浮点计算

1
2
3
a=59
b=60
awk 'BEGIN{printf "%.2f\n",('$a'/'$b')}'


参考: