Linux运维常用脚本:巡检、日志清理与定时任务实战

发布时间:2026/9/29 16:26:28
Linux运维常用脚本:巡检、日志清理与定时任务实战 简介面向Linux运维人员与初学者的常用脚本集合聚焦日常高频重复操作帮助读者通过现成脚本快速完成批量管理、服务部署、日志处理与系统监控等任务。资源共20个文件以19个可直接执行的sh脚本为主另含1个nginx.conf配置示例压缩包整体仅12KB小巧轻量便于下载后按需取用。脚本内容覆盖批量创建用户并设置密码、批量检测网站异常、远程批量执行命令、一键部署LNMP、Tomcat项目自动发布、Dos攻击自动屏蔽、MySQL数据库备份及主从同步状态监控、nginx访问日志按天切割与分析、服务器资源利用率查看、异常进程定位等场景基本囊括中小规模运维工作中的典型需求。目前已吸引81人学习下载对于想提升脚本化运维能力或快速搭建自动化维护体系的读者来说是一份值得参考的实用工具包。1. Linux 运维脚本不是图省事是给自己留一条半夜能走通的路在 Linux 服务器上做运维最怕的不是故障本身而是故障来了你还在用眼睛一行行翻top、df、last的输出把半小时花在「确认现状」上。所谓运维脚本说到底就是把那些每天重复、但又必须做的动作固化成一套可复用的命令集合——磁盘快满了自动清、日志按周期轮转、备份任务跑完自己核对结果。这份《Linux运维常用脚本》就是干这个的。它覆盖系统巡检、日志清理、磁盘监控、服务管理和安全留痕几个高频场景适合刚接手服务器的新人也适合每天要维护几十台机器、不想再被重复劳动消耗的老手。和单条命令不同脚本能让你在凌晨两点被电话叫醒时只敲一条命令就拿到整台服务器的家底。2. 脚本资源地图拿到手先搞清楚每段脚本该在哪个场景下用2.1 资源骨骼不是总行数而是按场景分好的目录很多刚接触脚本集合的人第一反应是打开文件从头读到尾把每个脚本都看一遍。我建议你不要这么做。这一批脚本的价值不在行数而在分类——它是按「日常巡检、日志清理、磁盘监控、安全备份、服务管理」几个方向组织起来的。你拿到手先看目录结构把脚本名和它对应的场景对号入座再用的时候才找得到。理解这批脚本还有一个更重要的点它是给你做「底稿」用的不是让你原样照搬的。每台服务器的环境不一样目录路径、服务名、保留天数、告警阈值都不同。你拿到脚本后的第一件事是把里面写死的路径和阈值改成你自己机器上的实际值然后在测试环境跑一遍确认输出正常再上生产。这一步做扎实了后面才不至于在出故障时才发现脚本根本不能跑。2.2 每一类脚本解决的真实问题与使用时机这几类脚本里我最建议你先用好的是系统巡检。它解决的是一个很朴素的问题每天早上到工位打开终端想知道昨晚服务器有没有异常CPU 有没有飙过磁盘还剩多少有没有人半夜登录过。这类脚本的核心就是把uptime、free、df、last、ss这些命令的输出汇总成一条带时间戳的记录写进一个统一的日志文件里你只需要cat这个文件就能完成复查。日志清理脚本则对应另一个场景服务器跑久了/var/log下的旧日志越堆越多nohup.out动辄几个 GB。这类脚本的关键不是「删得勤」而是「删得有依据」——按天保留、按文件数量保留、按磁盘剩余空间触发三种模式各有适用条件。磁盘监控脚本更像一个哨兵它周期性地检查分区使用率超过阈值就把告警写进日志甚至调用mail或 webhook 发出来。安全备份类脚本则在「防丢数据」和「防被黑不留痕」两个方向分别做动作前者管快照和数据库导出后者管登录记录和文件变更记录。拿到资源后先对照这个分类确认自己最缺哪一块优先把那部分脚本跑通再逐步扩展到其他方向。不要试图一天之内全部部署完成运维脚本是越用越完善的东西不是一次装完的软件包。3. 系统巡检脚本实战一条命令看清一台服务器一晚上的状态3.1 巡检脚本的标准结构与输出格式巡检脚本是所有运维脚本里性价比最高的一段因为它改动最小、见效最快。它的逻辑很简单把多步检查压缩成一条命令把结果按固定格式输出。下面是我在这个资源基础上改过的一个版本完整覆盖了 CPU、内存、磁盘、负载、登录和监听端口这几项最核心的检查。#!/bin/bash # sys_check.sh - 服务器巡检脚本适合每天早上人工复核一次 # 用法: ./sys_check.sh TS$(date %Y-%m-%d %H:%M:%S) HOST$(hostname) echo $HOST system check at $TS # 1. 负载与开机时长: uptime 的 load average 三个值 echo --- load --- uptime # 2. 内存用量: free -m 的 available 字段是真正可用内存 echo --- memory --- free -m | awk NR1 || NR2 {print $1, $2, $3, $7} # 3. 磁盘空间: 只看根分区和 /data 这类业务分区 echo --- disk usage --- df -h | grep -E ^(/dev/|/data|Filesystem) || df -h # 4. 最近登录记录: last 只保留 5 条能看到异常登录才有意义 echo --- recent logins (5) --- last -5 # 5. 对外监听端口: 用 ss 而不是 netstat echo --- listening ports --- ss -tlnp 2/dev/null | head -20 # 6. 是否有异常高负载进程 echo --- top 5 cpu procs --- ps aux --sort-%cpu | head -6脚本每跑一次你在终端里就能看到这台机器的完整快照。负载、内存、磁盘、登录、端口、进程六项信息全部齐了。注意我在这里做了两个细节处理一是free只看 available 列因为free的输出里 cached 会算进 used新手经常因此误判内存告急二是监听端口用ss而不是netstat现代发行版里 netstat 经常没装ss是 iproute2 包自带的一定在。脚本里head -20的位数可以自己调如果这台机器跑了很多服务可以放宽到head -30。3.2 把巡检脚本串成定时任务并在 30 秒内人工复核脚本写好了还要解决「谁去跑它」的问题。常见做法是把检查结果追加到一个日志文件再用crontab固定在每天早上去执行。注意追加用的是而不是否则每天的数据会把前一天覆盖掉你就失去了对比观察的能力。# 追加输出到 /var/log/server_check.log echo ----------------- $(date) ----------------- /var/log/server_check.log /opt/scripts/sys_check.sh /var/log/server_check.log 21每一次跑完日志里多出一段完整记录。这样早上一到工位只需要执行cat /var/log/server_check.log | tail -60几十秒就能把昨晚的情况过完。对比几天前的同一时段数据还能看出负载是不是在慢慢爬升——这种趋势往往比瞬时告警更有价值。这里有一个容易被忽略的参数细节巡检脚本里所有命令都要用绝对路径或者在脚本开头显式声明 PATH。crontab执行脚本时的环境变量和手动执行不一样它的 PATH 只有/usr/bin:/bin而ss一般在/usr/sbin/ss。如果你发现 crontab 里跑脚本前面检查都正常唯独端口那一栏是空的多半就是 PATH 的问题。解决方式很简单在脚本开头加一行export PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin一劳永逸。4. 日志与磁盘的自我清理清理脚本的参数设计与 crontab 落地4.1 按保留周期和阈值双条件触发清理服务器跑久了最先爆掉的往往不是数据盘而是日志分区。这个清理脚本的核心设计是双条件触发先判断磁盘使用率有没有超过阈值超过才进入清理逻辑清理时再按保留天数删除旧日志。只按天数删可能在日志很小的时候也每天做无用扫描只按阈值删又可能在磁盘满了之后才后知后觉没有提前量。双条件的设计就是为了兼顾两头的风险。下面这段清理脚本是资源里比较有代表性的一段我加了 dry-run 开关先看它会删什么确认无误再真正执行。#!/bin/bash # log_clean.sh - 按磁盘阈值保留天数双条件清理日志 # 用法: ./log_clean.sh # 真正清理 # ./log_clean.sh --dry-run # 只列出将要删除的文件不实际删除 THRESHOLD80 # 分区使用率超过 80% 才清理 KEEP_DAYS7 # 保留最近 7 天的日志 LOG_DIRS/var/log /opt/apps/*/logs # 可填多个目录用空格隔开 DRY_RUN0 if [ $1 --dry-run ]; then DRY_RUN1 fi # 检查脚本所在的磁盘分区使用率 USAGE$(df -h / | awk NR2 {print $5} | tr -d %) echo current disk usage: ${USAGE}% if [ $USAGE -lt $THRESHOLD ]; then echo disk usage below threshold, skip cleaning exit 0 fi # 进入清理逻辑: 按 mtime 找超过 KEEP_DAYS 天的 .log 和 .out 文件 for dir in $LOG_DIRS; do FILES$(find $dir -type f \( -name *.log -o -name *.out \) -mtime ${KEEP_DAYS}) for f in $FILES; do if [ $DRY_RUN -eq 1 ]; then echo [dry-run] would remove $f else rm -f $f echo removed $f fi done done这里$USAGE是从df -h /的第二行第五列提取百分比数字tr -d %去掉百分号方便做数值比较。注意-lt是小于符号我习惯把阈值判断写成「低于阈值就跳过清理」而不是「高于阈值就清理」这样脚本默认行为偏保守不清错东西。循环里对每个目录用 find 找*.log和*.out两类文件-mtime 7表示只看修改时间在 7 天之前的内容。如果你有用 logrotate 管理日志的习惯这里的清理目标和 logrotate 的旧归档文件可能存在重叠建议先在 develop 环境跑 dry-run 确认一次再上生产。4.2 定时任务落地与 dry-run 验证清理脚本和巡检脚本不一样巡检是给人看的清理是机器自己执行的所以定时频率和安全性要求都更高。一般做法是放在每天凌晨低峰期跑一次比如 3 点半。这个时间业务流量最低日志写入最少清理时不容易碰到正在写的文件。# crontab 写法: 每天 3:30 执行日志清理 30 3 * * * /opt/scripts/log_clean.sh /var/log/log_clean.log 21 # 每天 3:10 先跑巡检巡检和清理错开时间避免 IO 高峰叠加 10 3 * * * /opt/scripts/sys_check.sh /var/log/server_check.log 21两个任务相隔 20 分钟避免两个脚本的磁盘扫描同时进行造成 IO 抖动。上线前我的习惯是连续三天先跑--dry-run每天看一眼它列出的待删文件确认没有误伤最近正在写的日志再把 dry-run 参数去掉。特别是那些边写边删的特殊场景比如某些应用打开了日志文件句柄用rm -f删掉文件后进程还在往被删的 inode 里写数据磁盘空间并不会立即释放这个问题在下一章的排查部分会专门展开。你对手里的脚本做改动后也可以先用 dry-run 模式检查一次再部署。脚本资源里如果自带了这个参数就用现成的没有的话自己加一个DRY_RUN标记也不复杂。这算是我做运维之后最后悔没早学会的事情之一——所有删除类操作上线前强制走一遍只列不删的验证。5. 常见排查定时任务没跑、循环炸了这类故障怎么看5.1 crontab 环境变量缺失导致脚本部分功能静默失效现象脚本手动执行一切正常放进 crontab 后某些命令的输出是空的比如巡检脚本里ss -tlnp那一段在定时执行时没有任何结果其他段落都正常。原因crontab执行脚本时的 PATH 比交互式终端少很多默认只有/usr/bin:/bin。像ss这种位于/usr/sbin/ss的命令在 crontab 环境下直接调用是找不到的。脚本里其他命令比如uptime、free都在/usr/bin下所以没受影响问题只暴露在个别命令上。解决在脚本开头显式声明完整的 PATH 环境变量不要依赖交互式 shell 的继承。我一般这样写export PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin这个坑最恶心的地方在于它不会报错日志里看不到 command not found只有输出缺失。排查这类问题的方式是看 crontab 的重定向日志文件如果某一项输出为空但其他项正常优先怀疑 PATH而不是怀疑脚本逻辑。5.2 find 配合管道时变量丢失子 shell 的隐性问题现象在脚本里用find ... | while read line循环处理文件列表循环体内对变量赋值循环结束后这个变量为空。比如统计清理了多少文件统计数字打印出来是 0。原因while read在管道右侧会进入子 shell 执行循环体内的变量修改只在子 shell 内生效父 shell 拿不到。这是 bash 管道机制决定的不是脚本逻辑写错。解决用进程替换代替管道让 while 在父 shell 作用域里运行# 错误写法: 循环里的 count 外面读不到 # find /var/log -name *.log | while read f; do # count$((count1)) # done # echo cleaned $count # 永远输出 0 # 正确写法: 用进程替换 (find ...) count0 while read -r f; do rm -f $f count$((count1)) done (find /var/log -name *.log -mtime 7) echo cleaned $count进程替换 (commands)是这个场景的推荐写法它让find的输出仍然作为循环输入但循环体运行在父 shell 里循环内变量修改得以保留。另一个更稳妥的替代方案是find ... -delete直接在 find 内完成删除并配合-print计数但需要额外处理计数逻辑。这个坑在写清理类脚本时非常高频你手里的资源如果有管道的写法建议改成这种形式再使用。5.3 删除正在被写入的日志空间不释放反而把文件删成黑洞现象清理脚本执行后df -h查看磁盘使用率没有下降有时不降反升。检查发现日志文件确实被删了但分区可用空间没恢复。原因进程还持有被删除文件的文件句柄。rm -f只是把文件名从目录里摘掉如果某个进程仍然打开着这个文件文件占用的 inode 和磁盘块不会被释放直到进程关闭句柄。日志场景里应用进程长时间运行句柄不关空间就永远不还给你。解决处理这类被占用的日志文件先找到持有句柄的进程然后决定是重启进程还是用truncate将文件长度清零。一般日志场景用 truncate 更安全# 找到占用日志文件句柄的进程 lsof L1 /var/log/app.log # 方案一: 清空文件内容进程句柄不变磁盘空间立即释放 truncate -s 0 /var/log/app.log # 方案二: 确认是运行中的服务日志且服务可以安全重启则直接重启服务 systemctl restart app-servicelsof L1专门列出被删除但仍被进程打开的文件。truncate 清空后进程继续往空文件里写内容空间使用从零开始重新增长比重启服务的影响小得多。清理脚本里如果要加这个处理应该先用 lsof 判断文件是否被占用被占用的走 truncate 分支没被占用的才走 rm 分支。5.4 同步删除多条路径时忽略了通配符未匹配的情况现象脚本里写rm -rf /data/backup/*/2023_old这类路径某天发现命令执行成功但没有删掉任何文件而且原本不该删的目录被删了。原因bash 通配符在目录不存在时会保持字面量传给 rmrm -rf拿到一个不存在的路径不会报错更不会删除。但如果/data/backup/*匹配到了你没想到的子目录后面拼接的路径就可能在误删范围内。这一类问题本质是对通配符展开结果缺少检查。解决所有包含通配符的删除命令先展开打印确认再执行。脚本里写成两段式TARGETS$(ls -d /data/backup/*/2023_old 2/dev/null) if [ -z $TARGETS ]; then echo no target found, skip /var/log/clean.log else echo $TARGETS /var/log/clean.log # 人工确认后放开下面这行 # rm -rf $TARGETS fi先用ls -d拿到真实匹配到的路径列表确认后才放开删除动作。这个习惯在磁盘清理和日志清理这两个脚本里都应该推广——凡是脚本自动执行的删除都要有日志留痕即使某天删漏了你还能根据日志回头查。6. 进阶用法把常用脚本收成一个带菜单的入口配合统一日志落地脚本数量一多问题就从「有没有脚本」变成「记不记得住脚本名和参数」。我的做法是把资源里的脚本串成一个菜单式工具箱你平时只需要记住一个命令ops.sh进去用数字选择要执行的功能。这个思路特别适合管理那些低频但重要的脚本——比如手动备份、安全巡检平时想不起来真要用时又想不起具体名字。#!/bin/bash # ops.sh - 运维脚本菜单入口 PS3请选择要执行的操作: options(系统巡检 日志清理 本月备份 退出) select opt in ${options[]}; do case $opt in 系统巡检) /opt/scripts/sys_check.sh ;; 日志清理) /opt/scripts/log_clean.sh --dry-run ;; 本月备份) /opt/scripts/backup_manual.sh ;; 退出) break ;; *) echo 输入无效请重试 ;; esac doneselect是 bash 内置的菜单语法配合PS3定义提示符。注意我把日志清理默认设为--dry-run而不是直接执行删除——宁可多一步确认也不要误删。菜单脚本还可以加一个统一的日志记录函数把每次操作的时间、执行用户、选择的功能写进/var/log/ops_history.log这样后续排查问题时有据可查。这个菜单不需要很复杂能把脚本聚合起来就已经解决了一大半痛点。如果你管理的是多台机器还可以把ssh调用包在菜单脚本里选择目标主机再选择功能组合成一个简易的批量运维入口。最后说一个我自己的教训以前我写完脚本测一次能跑就扔到服务器里结果过了两个月 crontab 报错才发现是环境变量被系统升级改了。从那以后我每次上线脚本都强制走一遍「手动执行—dry-run 验证—crontab 定时—查看次日日志」四步流程一个环节不通过就返回去改代码绝不跳过。这套流程看着笨但能省掉后面排查时的好几个通宵。希望帮到你。本文还有配套的精品资源点击获取