ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux运维常用脚本:磁盘告警、日志清理与健康检查自动化

Linux运维常用脚本:磁盘告警、日志清理与健康检查自动化 简介面向Linux运维工程师的常用脚本合集聚焦服务器日常管理、备份、监控与自动化部署等高频场景可帮助运维人员减少重复手工操作提升批量维护和故障排查效率。资源包共20个文件以.sh脚本为主19个另附1个nginx.conf配置模板rar压缩包仅12KB轻量易用适合在Linux生产或测试环境中快速部署与二次修改。目前已有82人学习下载。脚本覆盖较广如MySQL数据库备份单循环与多循环、批量创建用户并设置密码、批量主机远程执行命令、LNMP一键部署、PHP与Java项目自动发布、Dos攻击自动屏蔽、MySQL主从同步监控、nginx日志按天切割与分析、网卡流量与系统资源实时查看、磁盘利用率监控、高CPU/内存进程定位、目录变化监控与文件同步等。这些功能贴近日常运维高频场景适合初学与进阶运维者参考借鉴。1. Linux运维常用脚本每天少敲两百次命令从一份可靠脚本库开始刚接手一批 CentOS 7 和 Ubuntu 20.04 混合服务器时我每天大半时间都耗在重复动作上看磁盘、清日志、重启服务、改配置文件、批量传文件。真正的问题不是不会敲命令而是同样的操作被反复执行每次都要重新回忆参数还要担心漏掉哪台机器。于是我把高频操作收敛成一套 Linux 运维常用脚本覆盖磁盘告警、日志清理、服务健康检查和批量执行四类场景。这套东西不解决架构问题但能把日常巡检时间从两小时压到二十分钟适合刚转行做运维、以及被大量重复工作淹没的初级运维工程师。脚本的本质是把你脑子里的经验固化成文件让机器按固定节奏替你干活。下面我会按场景拆开讲每段都给出可直接落地的脚本和参数说明并把我在生产环境踩过的坑一并标注出来。2. 磁盘与日志清理脚本先保住磁盘再谈稳定性2.1 磁盘告警脚本用 df 和 inode 双指标判断真实风险磁盘满是最常见的故障诱因但只看df -h会漏掉一类隐蔽问题inode 耗尽。当服务器上小文件数量暴增比如临时文件、邮件队列、容器日志碎片即使空间还有剩余文件系统也无法创建新文件。我一般会同时检查空间使用率和 inode 使用率任一超过阈值就告警。#!/bin/bash # 磁盘空间与 inode 双维度告警脚本 # 使用方法配合 crontab 每 10 分钟执行一次 THRESHOLD85 # 空间使用率告警阈值(%)按业务调整 INODE_THRESHOLD85 # inode 使用率告警阈值(%) df -P | awk NR1 $50 $THRESHOLD {print 空间告警:, $6, $5} df -iP | awk NR1 $50 $INODE_THRESHOLD {print inode告警:, $6, $5}这段脚本的关键是df -P参数它强制以 POSIX 格式输出避免超长挂载点换行导致awk解析错位。NR1跳过表头$50把百分比字符串转成数字。告警消息可以直接接mailx或写入/var/log/disk_alert.log生产环境建议走企业微信或钉钉机器人 webhook别依赖服务器本地邮箱很多最小化安装根本没配邮件服务。另一个容易翻车的地方是根目录/和/boot分区。/boot空间很小内核更新几次就满而系统不会自动清理旧内核。我习惯把/boot单独加入监控列表阈值降到 70%并及时提醒yum autoremove或apt purge旧内核。2.2 日志清理策略别用 find -delete 直接上生产日志文件是磁盘增长的最大推手尤其 Nginx、Tomcat、应用自定义日志。最稳妥的做法是交给 logrotate 按天切割、按周清理但很多中小团队根本没配 logrotate日志无限增长最后只能手动砍。#!/bin/bash # 按天清理超过 N 天的日志文件保留 .log 和 .log.1.gz 最新两轮 LOG_DIRS/var/log/nginx /var/log/tomcat /data/applogs RETENTION_DAYS30 for dir in $LOG_DIRS; do if [ -d $dir ]; then find $dir -type f -name *.log -mtime $RETENTION_DAYS -delete find $dir -type f -name *.gz -mtime $RETENTION_DAYS -delete echo [$(date %Y-%m-%d %H:%M:%S)] cleaned $dir fi done-mtime 30匹配修改时间超过 30 天的文件-delete直接删除。这条命令在大多数场景可用但有三个坑不要对 NFS 挂载目录直接-delete网络文件系统上 find 删除遇到 IO 抖动会报错中断建议先-print生成清单再批量rm。文件名含空格或特殊字符时-delete没问题但如果先ls再管道给xargs rm必须用-print0和xargs -0。应用还在写日志时删除正在写的文件文件句柄不释放磁盘空间不会真正回收。需要让应用重新 open 日志文件常见做法是/usr/bin/truncate -s 0先清空再谈删除或者配合kill -USR1让 Nginx 重新打开日志。表日志类型与推荐保留周期日志类型保留天数处理方式注意事项Nginx 访问日志715logrotate 切割压缩按天切割避免单文件过大应用业务日志3060按天分目录归档按服务维度分开目录系统安全日志90180压缩存档审计需要保留时间长临时调试日志37直接清理开启 debug 后必清3. 服务健康检查与自愈脚本把「探测→处理→通知」串成闭环3.1 端口探测脚本不迷信 systemd自己维护兜底systemd 的Restartalways能在进程崩溃时拉起服务但遇到假死进程还在、端口不响应、CPU 100% 但请求队列堵死就无能为力。我习惯在 crontab 里跑一层端口探测配合健康检查接口检测失败就执行重启动作。#!/bin/bash # 检测指定端口 TCP 连通性失败则重启服务并记录日志 PORT8080 SERVICE_NAMEtomcat RESTART_CMDsystemctl restart tomcat CHECK_TIMEOUT5 if ! timeout $CHECK_TIMEOUT bash -c echo /dev/tcp/127.0.0.1/$PORT 2/dev/null; then echo [$(date %F %T)] $SERVICE_NAME port $PORT is unreachable, restarting... /var/log/service_check.log $RESTART_CMD sleep 3 if timeout $CHECK_TIMEOUT bash -c echo /dev/tcp/127.0.0.1/$PORT 2/dev/null; then echo [$(date %F %T)] $SERVICE_NAME recovered after restart. /var/log/service_check.log else echo [$(date %F %T)] $SERVICE_NAME restart FAILED, please check manually. /var/log/service_check.log fi fi/dev/tcp/是 bash 内置的虚拟设备echo /dev/tcp/127.0.0.1/8080相当于发起一次 TCP 连接连接成功则命令返回正常失败则返回非零。外层timeout 5防止端口处于半开状态时脚本挂死。生产环境注意两点探活目标别写127.0.0.1某些服务只在0.0.0.0监听时本地回环也能通但外部实际不可达更靠谱的做法是探测域名解析后的真实 IP或者直接请求应用的健康检查 URI。另外重启动作要有幂等性设计。脚本被 crontab 每 5 分钟执行一次如果服务反复崩溃每次检测到失败都会重启可能引发重启风暴。我在生产上加了一个计数器同一小时内重启超过 3 次就不再自动拉起改为发告警等人工介入。3.2 三分钟看懂健康检查脚本的退出码设计脚本能否可靠地融入现有监控体系很大程度上取决于退出码写得好不好。很多初学者写的检查脚本永远返回 0监控平台永远显示正常实际上服务早就挂了。下面这段检查进程数加退出码的写法比较规范#!/bin/bash # 检查进程是否存在并按监控约定返回退出码 # 0正常, 1进程不存在, 2进程数异常 PROC_NAMEnginx EXPECTED_COUNT2 COUNT$(pgrep -f $PROC_NAME | wc -l) if [ $COUNT -eq 0 ]; then echo 进程不存在: $PROC_NAME exit 1 elif [ $COUNT -lt $EXPECTED_COUNT ]; then echo 进程数不足: $COUNT (期望 $EXPECTED_COUNT) exit 2 fi echo 检查通过, 进程数: $COUNT exit 0pgrep -f匹配完整命令行参数比pgrep nginx更准确——避免只按进程名匹配时漏掉带配置路径启动的实例。wc -l统计匹配行数这里的一个隐藏坑是pgrep -f nginx会匹配到执行该脚本的bash进程本身因为命令行里包含 nginx 字符串所以结果会额外加 1。解决办法是排除自身pgrep -f $PROC_NAME | grep -v $$或者直接pgrep -x nginx用精确进程名匹配。配合 Zabbix 或 Prometheus 的custom script监控项时退出码 1 和 2 会被映射成不同告警级别。这个习惯我从第一年做运维就养成了现在不管写多小的脚本出口处一定显式exit绝不让脚本自然落到底。3.3 配合 crontab 的定时策略与频率选择脚本写得再好调度频率错了照样出问题。我见过有人把磁盘检查设成每分钟执行一次结果df命令本身开销不大但后续脚本里如果还包含find日志扫描那 IO 压力就可能拖垮数据库服务器。经验值供参考磁盘和内存检查 510 分钟一次服务端口探活 15 分钟一次日志清理 1 天一次凌晨低峰期执行全量配置备份 1 天一次。最关键的是检查脚本本身要轻量不要在一个周期任务里同时跑 find 压缩 网络转发告警否则监控脚本就变成了新的故障源。4. 批量执行脚本一条命令把操作放到一百台服务器上4.1 PSSH 与 expect 的取舍先搞清你的集群有多少台机器机器少用 expect机器多直接上 psshParallel SSH这是我在管理 30 台和 300 台服务器时分别走的两条路。expect 适合处理只有三五台机器、且各机器密码不同的场景一旦超过二十台逐个写 expect 脚本本身就是灾难。#!/usr/bin/expect # expect 批量改密码并执行 uptime 示例 set timeout 10 set ip [lindex $argv 0] set pass [lindex $argv 1] spawn ssh root$ip uptime; df -h | head -5 expect { *password: { send $pass\r; exp_continue } *yes/no* { send yes\r; exp_continue } eof }exp_continue的作用是在收到密码提示后发送密码并继续等待下一个匹配模式。第一次连接时会出现yes/no指纹确认必须单独处理。这个脚本的问题也很明显密码明文写在脚本里而且每次连接都建立新会话效率很低。超过 10 台机器时连接耗时线性增长执行完一轮可能要十分钟。pssh 的写法则完全不同它维护一个长连接池并发执行几十台机器并行跑命令也就几秒到十几秒# 对 hostlist.txt 中所有机器并发执行 uptime pssh -h hostlist.txt -l root -i uptime # 带超时与并发数控制 pssh -h hostlist.txt -l root -t 5 -p 10 -i df -h-p 10控制并发数默认是 32网络带宽不足或目标机器性能差时建议调低到 1015。-t 5是单条命令超时时间防止某台机器 hang 住拖慢整体。pssh 的配套命令pscp可以用来批量分发文件-r递归传目录这比写 for 循环 scp 踏实得多。这里强调一下pssh 依赖 SSH 免密登录生产环境必须用密钥认证密码认证反而容易触发安全审计问题。4.2 shell 循环加 ssh 的简化实现小规模机器不引入额外依赖如果公司安全要求严格无法安装 pssh或者只是临时对三四台机器操作写一个简单的 for 循环也能解决问题。这种方式在「Linux 脚本」语境里最常被搜索到实现思路是逐个连接并执行。#!/bin/bash # 用 for 循环对多台机器执行命令 HOSTS192.168.1.10 192.168.1.11 192.168.1.12 SSH_USERroot CMDuptime hostname df -h | tail -1 for host in $HOSTS; do echo $host ssh -o StrictHostKeyCheckingno -o ConnectTimeout5 $SSH_USER$host $CMD || echo 连接失败: $host done-o StrictHostKeyCheckingno避免首次连接交互确认时脚本卡住-o ConnectTimeout5让不可达主机在 5 秒内超时不会白白等待 TCP 默认的 120 秒。这个写法适合一次性任务优势是零依赖但有两个硬伤串行执行机器多时耗时不可接受输出混杂难以区分哪段输出来自哪台机器。中间加个分隔行只能勉强解决辨识问题真要规模化还是上面说的 pssh 更靠谱运维脚本的第一原则是顺手且不给自己添乱。5. 运维脚本避坑指南三条血泪经验帮你少走弯路5.1 脚本开头少了 set -e出错后继续往下跑后果很严重我踩过最疼的一次坑写部署脚本时前一步rm -rf /data/old_backup因为目录不存在返回了非零状态但脚本没有set -e继续执行了下一步移动新包的命令最后把新包覆盖了旧包导致发布回滚时找不到可用版本。#!/bin/bash set -e set -u # 上述两个选项让脚本在出错或变量未定义时立即退出set -e表示任何命令返回非零状态立即退出set -u表示使用未定义变量时报错。但注意set -e有例外if条件、while条件、或||连接的左侧命令这时要用显式判断。我在关键步骤还会加set -o pipefail确保管道中任何一段失败都被捕获比如cmd1 | cmd2中cmd1失败但cmd2成功时最终退出码是 0pipefail会修正为失败。5.2 CRLF 换行符导致脚本在 Linux 上执行报错光看报错完全摸不着头脑在 Windows 上编辑脚本传送到 Linux 后bash script.sh会报$\r: command not found。原因是 Windows 编辑器默认使用CRLF作为行尾Linux 只认LF。遇到这个报错先别怀疑语法用file命令或cat -A script.sh | grep \r查一下换行符。# 快速转换 CRLF 为 LF sed -i s/\r$// script.sh这个坑在运维中非常高频尤其是团队用 Git 跨平台协作时。解决之后建议在仓库里加一个.gitattributes文件强制文本文件统一用 LF或者在编辑器里设置按 LF 保存。我遇到过远程主机上脚本权限没问题、执行就是报错的诡异情况排查半天发现是换行符的问题当场差点把键盘拍烂。5.3 脚本里有交互式 sudo 或 su 提示放到 crontab 里就失效脚本在终端里手动执行一切正常放进 crontab 后却报权限错误或找不到命令。核心原因有两个cron 环境下的 PATH 是最小化的/usr/local/bin可能不在其中导致命令找不到另一个是 sudo 需要 TTY而 cron 默认没有分配终端。# crontab 里执行脚本的正确姿势关键在 PATH 和重定向日志 */5 * * * * /usr/bin/env bash /opt/scripts/check_disk.sh /var/log/check_disk.log 21脚本开头强制定义 PATHexport PATH/usr/local/bin:/usr/bin:/bin这样即使 cron 环境不同也能执行。如果需要 sudo在/etc/sudoers里给对应用户配置NOPASSWD权限比如ops ALL(ALL) NOPASSWD: /usr/bin/systemctl restart nginx而不是在脚本里写echo password | sudo -S密码明文不仅不安全还可读性极差别人看到这种脚本会说你运维基本功没练到位。6. 把常用脚本组织成自己的工具箱模块化写法与版本管理6.1 封装一个函数库 script-lib.sh不同用途的脚本按需加载等脚本数量超过十几个平铺文件的方式就不好维护了。我后来把公共函数统一放进一个lib.sh每个业务脚本开头source /opt/scripts/lib.sh。这样改日志函数或告警函数时只改一处所有脚本自动生效。#!/bin/bash # lib.sh 公共函数库 # 用法: source /opt/scripts/lib.sh log_info() { echo [$(date %Y-%m-%d %H:%M:%S)] [INFO] $* } log_error() { echo [$(date %Y-%m-%d %H:%M:%S)] [ERROR] $* 2 } send_alert() { local msg$1 # 这里接企业微信/钉钉 webhook, 注意 URL 在服务器上保留安全 curl -s -X POST https://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyYOUR_KEY_FROM_ENV \ -H Content-Type: application/json \ -d {\msgtype\:\text\,\text\:{\content\:\$msg\}} }变量$*是函数所有参数的组合2把错误信息写到标准错误。send_alert的 webhook key 不要写死在库里建议用环境变量引用比如${WEBHOOK_KEY:?webhook key not set}防止脚本被传到外部仓库时泄密。公共库的引入还有个好处是统一了退出码。每个脚本都在最后显式标注exit 0或exit $?配合set -e使用出错时立即停住日志里能看到最后一条执行到哪。这套方式和 Ansible 的模块设计思路类似不追求高级配置管理但胜在零依赖、一台机器一个 bash 就能跑。6.2 用 20 分钟做一个自检跑通一份「新服务器验收脚本」工具箱建好之后最好写一个自检流程避免脚本攒了一堆、真到用时发现某个函数名拼错、或者某段逻辑只在自己机器上跑得通。我每次交付脚本前都会跑一遍下面的验收清单#!/bin/bash # 新机器基础环境验收脚本 # 检查 CPU 架构、内存、磁盘、网络连通性、端口监听 echo CPU 信息 lscpu | grep -E Architecture|Model name|CPU\(s\) echo 内存信息 free -h echo 磁盘与文件系统 df -hT | head -10 echo 关键端口监听状态 ss -tlnp | grep -E :22|:80|:443|:3306|:8080df -hT多了一个-T参数可以把文件系统类型也打印出来排查 NFS 或 overlay 时特别有用。ss -tlnp是netstat的现代替代版显示监听端口和对应进程 PID比netstat输出更简洁且性能开销低。如果发现脚本执行时间和预期不符在脚本外面用time bash xxx.sh测一下一个巡检脚本跑超过 30 秒就要审视里面的命令是否太低效是不是被 sleep 卡住了。工具脚本本身要版本管理。我习惯在脚本头部注释里写# Author: ops; Last Modified: 2025-xx并纳入 Git 管理每台服务器从 Git 拉取到/opt/scripts配合 crontab 做定时同步。时间久了自然形成自己的最佳实践库基本不会出现找不到脚本、不知道脚本改过什么的情况反而成了新同事入职时最快上手的资料。这是我个人比较推荐的脚本管理方式希望你也能找到适合自己团队的节奏这套思路能帮上你就好。本文还有配套的精品资源点击获取
返回列表