实用向:Linux Shell 脚本实现 CPU / 内存 / 硬盘 + IO / 网络多指标告警(支持 163/QQ/139 邮箱)
1创建一个告警脚本
export LANG=en_US.UTF-8 # 设置语言环境为英文,避免中文输出导致的乱码问题
2配置邮箱
smtp_server="smtp.qq.com" # QQ邮箱SMTP服务器地址
smtp_port="465" # SMTP服务端口(SSL加密)
sender="3159862842@qq.com" # 发件人邮箱(你的QQ邮箱)
sender_pwd="ixpxrqrwxykmdhci" # 邮箱授权码(不是登录密码,需要在邮箱设置中获取) receiver="3159862842@qq.com" # 收件人邮箱(这里和发件人相同,即发送给自己)
subject="[告警]CPU/内存/硬盘超标" # 邮件主题
3监控配置
3.1监控CPU使用率
cpu_idle=$(top -bn1 | awk '/^%Cpu/ {print $8}') # 获取CPU空闲率(top命令批处理模式) cpu_usage=$(echo "100 - $cpu_idle" | bc | awk '{printf "%.0f", $0} ') # 计算CPU使用率(100-空闲率)
bc
用于处理浮点运算(带小数的数字运算)
%.0f取整
3.2监控内存使用率
mem_total=$(free -m | grep Mem | awk '{print $2}') # 总内存(MB)
mem_used=$(free -m | grep Mem | awk '{print $3}') # 已使用内存(MB)
mem_usage=$(echo "scale=0;$mem_used / $mem_total * 100" | bc) # 计算内存使用率(已用/总内存*100)
scale=0
:设置 bc
的计算精度为 0(不保留小数)
3.3监控硬盘使用率
disk_usage=$(df -h / | awk 'NR==2 {gsub(/%/,""); print $5}' ) # 获取根目录使用率(去除百分号)
gsub(/%/,"")
:去除字符串中的百分号 %
确保变量为整数,避免比较错误
3.4监控io await
if command -v iostat &> /dev/null; then
# 获取所有磁盘平均await值(取2位小数)
io_await=$(iostat -x 1 5 | awk '/^avg-cpu/ {getline; getline; sum=0; count=0} /^[vhs]d/ {sum+=$10; count++} END {printf "%.2f", sum/count}')
else
echo "警告:未安装iostat,请先安装sysstat包"
io_await=0
fi
getline 跳过
%.2f 取两位小数
3.5监控网络流量
#获取有效网络接口
interface=$(ip -br link show | grep -v LOOPBACK | awk '{print $1}' | head -n 1)
#判断接口是否存在
if [ -n "$interface" ]; then
采集流量数据
read rx_bytes1 tx_bytes1 <<< $(cat /sys/class/net/$interface/statistics/{rx_bytes,tx_bytes})
sleep 1
read rx_bytes2 tx_bytes2 <<< $(cat /sys/class/net/$interface/statistics/{rx_bytes,tx_bytes})
计算流量速率
rx_mb=$(echo "scale=2; ($rx_bytes2 - $rx_bytes1) / 1024 / 1024" | bc)
tx_mb=$(echo "scale=2; ($tx_bytes2 - $tx_bytes1) / 1024 / 1024" | bc)
else
rx_mb=0; tx_mb=0
fi
ip -br link show
:以简洁模式显示所有网络接口
grep -v LOOPBACK
:排除回环接口(lo)
awk '{print $1}'
:提取接口名称(第一列)
head -n 1
:取第一个有效网络接口(通常是主要网卡)
/sys/class/net/$interface/statistics/
:系统内核提供的网络统计文件
rx_bytes
:接收(下载)的总字节数
tx_bytes
:发送(上传)的总字节数
两次采集间隔 1 秒(sleep 1
),用于计算每秒速率
计算 1 秒内的字节变化量(rx_bytes2 - rx_bytes1
)
转换单位:字节 → KB(÷1024)→ MB(÷1024)
scale=2
:保留两位小数,结果分别存入下载速率(rx_mb
)和上传速率(tx_mb
)
4告警逻辑判断
alert_content="[告警]$(date '+%Y-%m-%d %H:%M:%S')\n\n" # 初始化告警内容,包含时间戳 alert_trigger=0 # 告警触发器(0=正常,1=需告警) # CPU使用率超过80%时触发告警
if [ $cpu_usage -gt 80 ]; then alert_content="${alert_content} CPU使用率超标: ${cpu_usage}% (阈值80%) \n" alert_trigger=1 fi # 内存使用率超过80%时触发告警(原脚本这里有重复的alert_trigger=1,需要修正)
if [ $mem_usage -gt 80 ]; then alert_content="${alert_content} 内存使用率超标: ${mem_usage}% (阈值80%) \n" alert_trigger=1 fi # 硬盘使用率超过80%时触发告警
if [ $disk_usage -gt 80 ]; then alert_content="${alert_content} 根目录使用率超标:${disk_usage}% (阈值80%) \n" alert_trigger=1 fi
# IO await告警
if (( $(echo "$io_await > 50" | bc -l) )); then
alert_content="${alert_content} IO await超标: ${io_await} (阈值50)\n"
alert_trigger=1
fi
# 网络流量告警
if (( $(echo "$rx_mb > $network_threshold" | bc -l) )); then
alert_content="${alert_content} 下载流量超标: ${rx_mb}MB/s (阈值${network_threshold}MB/s)\n"
alert_trigger=1
fi
if (( $(echo "$tx_mb > $network_threshold" | bc -l) )); then
alert_content="${alert_content} 上传流量超标: ${tx_mb}MB/s (阈值${network_threshold}MB/s)\n"
alert_trigger=1
fi
5.告警邮件发送
if [ $alert_trigger -eq 1 ]; then # 如果触发告警(alert_trigger=1)
echo -e "${alert_content}" | mailx -v \ -s "${subject}" \ -S smtp-use-starttls \ -S ssl-verify=ignore \ -S smtp-auth=login \ -S smtp="${smtp_server}:${smtp_port}" \ -S from="${sender}" \ -S smtp-auth-user="${sender}" \ -S smtp-auth-password="${sender_pwd}" \ ${receiver} # 记录告警日志
echo "$(date '+%Y-%m-%d %H:%M:%S') 告警已发送:${alert_content}" >> /var/log/sys_monitor.log else # 指标正常时记录日志
echo "$(date '+%Y-%m-%d %H:%M:%S') 指标正常:CPU=${cpu_usage}% 内存=${mem_usage}% 硬盘=${disk_usage}% IO await=${io_await} 下载=${rx_mb}MB/s 上传=${tx_mb}MB/s" >> /var/log/sys_monitor.log fi
echo -e "${alert_content}"
:准备邮件内容(-e
支持转义字符,如换行\n
)| mailx -v
:通过管道将内容传给mailx
命令(-v
显示详细发送过程,便于调试)- 邮件配置参数(
-S
用于设置mailx
选项):-s "${subject}"
:邮件主题(由变量subject
定义,如 “系统资源告警”)smtp-use-starttls
:启用 TLS 加密连接(安全发送邮件)ssl-verify=ignore
:忽略 SSL 证书验证(避免因证书问题发送失败,生产环境慎用)smtp-auth=login
:使用 login 方式进行 SMTP 认证smtp="${smtp_server}:${smtp_port}"
:SMTP 服务器地址和端口(如smtp.qq.com:587
)from="${sender}"
:发件人邮箱smtp-auth-user/password
:SMTP 认证的用户名(通常是发件人邮箱)和密码(或授权码)${receiver}
:收件人邮箱(可以是多个,用空格分隔)