ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

279个开箱即用Shell脚本合集:运维自动化与Linux实用工具详解

279个开箱即用Shell脚本合集:运维自动化与Linux实用工具详解

简介:这套资料汇集279个可直接使用的Shell脚本,覆盖DDoS攻击IP自动屏蔽、Linux邮件告警、MySQL单/多循环备份、Nginx访问日志按天切割与分析、网卡实时流量查看等常见运维场景,适合Linux/Unix系统管理员、运维工程师及Shell入门学习者参考使用,能够快速提升日常服务器管理与自动化巡检效率。资源为PDF格式文档,共1个文件,压缩包约4.69MB,内容以脚本说明与代码示例为主,便于按需翻阅和复制实践。已有154人学习下载,属于小巧实用的脚本合集资料。文档从实际生产需求出发,不仅给出完整脚本,还讲解日期获取、日志分析、iptables防火墙操作、mysqldump备份、cron定时执行等关键技术点,并提供了针对大型数据库的多级目录备份思路与Nginx日志异常识别方法,读者可在此基础上直接修改参数复用,或通过阅读代码掌握Shell脚本的编写逻辑与调试技巧。

1. 运维日常里那句“这活能不能写个脚本”:279个开箱即用的shell脚本合集

如果你管过几台Linux服务器,大概率遇到过这种场景:凌晨两点Nginx日志刷出大量异常IP、MySQL备份占满磁盘、上线新机器要手动配时区关防火墙调内核参数。这些活儿单个看都不难,难的是每次都手工来一遍。这份279个开箱即用的shell脚本合集,就是把运维里高频出现的操作场景——DDoS攻击防范、数据库备份、日志切割、系统初始化、进程监控、告警通知——全部脚本化,拿到手改几个变量就能跑。适合刚接触Linux运维的开发者照着学,也适合已经在生产环境摸爬滚打的老手直接挑脚本改改用。不少脚本甚至不需要理解内部原理,改个路径和账号就能用,真正意义上的开箱即用。

2. 脚本合集架构解析:按场景分类的运维工具箱

2.1 从“命令集合”到“功能模块”的归类思路

拿到脚本包的第一件事不是急着跑,而是先看目录结构。整个合集虽然叫“279个脚本”,但内部并不是散落的一堆文件,而是按运维场景做了功能归类,大致可以分成六类:安全防护类(DDoS检测、异常IP封禁、SSH防爆破)、数据备份类(MySQL单库/多库备份)、日志管理类(Nginx日志切割、访问分析、GC日志统计)、系统监控类(磁盘利用率、网卡流量、进程状态统计)、环境初始化类(时区同步、SELinux关闭、内核参数优化)、以及Python扩展类(企业微信告警、FTP客户端、SSH批量操作)。

这种归类的设计思路很实在:运维工作本质上就是“发现异常—定位原因—执行修复—事后追溯”的循环,每一类脚本对应其中一个环节。安全类负责发现问题,告警类负责通知人,备份类负责兜底,日志类负责事后排查,初始化类负责减少重复劳动。你用的时候不需要记住279个脚本各自叫什么,只需要先判断当前遇到的是哪类问题,再去对应分类里找。

2.2 三种技术栈的穿插:Bash为主、awk配合、Python补位

脚本包里的技术选型值得单独说一下。绝大多数脚本是纯Bash实现,这是对的——运维场景里Bash不需要额外装依赖、权限好控制、出错时输出直观。当你需要处理文本、统计日志、抽取字段时,脚本里大量使用awk和grep组合,这算是shell脚本的进阶用法。比如统计访问最多的IP,一条awk就能完成分组计数和排序输出。

还有少数场景用了Python,比如企业微信告警和FTP客户端。原因不难理解:企业微信API调用需要处理JSON、构造HTTP请求,Bash写起来又长又容易出错;FTP上传下载涉及socket操作和状态码判断,用ftplib库十行代码就搞定。所以这里的技术选型逻辑是:能用Bash解决的绝不用Python,Bash写着痛苦的场景再上Python。这种取舍对你自己组装脚本工具库很有参考价值。

2.3 脚本设计的通用套路:变量前置、判断兜底、日志留痕

翻多看几个脚本后你会发现它们有共同的设计模板。首先是变量集中写在脚本头部——数据库地址、用户名、密码、备份目录、日志路径,全都在顶部定义,改配置不用往下翻代码;其次是命令执行后都带判断,比如if ! mysqldump ... ; then echo "备份失败",这种做法防止脚本“静默失败”;再次是凡是封IP、删文件、改配置这类危险操作,一定会把操作记录追加到某个log文件里,方便事后追溯。

这个模板意识值得刻意练习。我自己早期写脚本习惯把所有路径写死在命令里,结果换个环境就要全文搜索替换,后来强制自己遵守“变量前置、结果判断、日志留痕”三条铁律,脚本的复用性明显上来了。这份合集里大部分脚本都遵守了这套规范,所以拿来改造成本很低。

3. 核心模块拆解:安全防护与数据备份的完整链路

3.1 DDoS攻击防范脚本:从日志异常到iptables封禁

这个脚本是合集里含金量比较高的一个,完整演示了“发现异常—自动处置—留痕审计”的安全闭环。先看核心实现:

#!/bin/bash DATE=$(date +%d/%b/%Y:%H:%M) LOG_FILE=/usr/local/nginx/logs/demo2.access.log ABNORMAL_IP=$(tail -n5000 $LOG_FILE |grep $DATE |awk '{a[$1]++}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 echo "$(date +'%F_%T') $IP" >> /tmp/drop_ip.log fi done

逻辑链路是:先取当前时间点(精确到分钟),从Nginx访问日志尾部5000条里过滤出当前时刻的请求,用awk按IP分组计数,访问次数超过10次的IP判定为异常,进入封禁流程。封禁前用iptables -vnL | grep -c检查该IP是否已在规则链里,避免重复添加,然后把封禁时间和IP追加写入/tmp/drop_ip.log。整个处理最巧妙的是用tail -n5000而不是全量扫描日志,既保证实时性又控制了性能开销。

这段脚本要落地到生产环境,需要根据实际场景调整三个地方:日志路径、触发阈值(10次/分钟在当前业务量下是否合理)、以及封禁动作是否需要改成调用云服务商的安全组API。如果你机器前面还套了一层CDN或者负载均衡,看到的所有请求IP都是转发节点的地址,那这个脚本就失效了,需要改成从http_x_forwarded_for字段取真实客户端IP。

3.2 MySQL数据库备份:单循环与多循环的取舍逻辑

备份脚本提供了两种模式,目的很明确——不同场景对恢复粒度的要求不一样。先看单循环版本:

#!/bin/bash DATE=$(date +%F_%H-%M-%S) HOST=localhost USER=backup PASS=123.com BACKUP_DIR=/data/db_backup DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys") for DB in $DB_LIST; do BACKUP_NAME=$BACKUP_DIR/${DB}_${DATE}.sql if ! mysqldump -h$HOST -u$USER -p$PASS -B $DB > $BACKUP_NAME 2>/dev/null; then echo "$BACKUP_NAME 备份失败!" fi done

这里有一个细节容易踩坑:show databases会返回所有库名,包括系统的information_schema、performance_schema和mysql库,所以后面必须用egrep把系统库排除掉,否则备份文件里会混入一堆用不到的系统数据。备份失败时脚本只是echo一句,这个处理在生产环境不建议照抄,最好改成把失败信息追加到日志文件再加告警通知。单循环的优点是快速、每个库一个文件,恢复时直接mysql < server.sql就行;缺点是如果某个库特别大,整个备份流程会被它拖住。

多循环版本则是对每个库下的每张表单独备份:

#!/bin/bash DATE=$(date +%F_%H-%M-%S) HOST=localhost USER=backup PASS=123.com BACKUP_DIR=/data/db_backup DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys") for DB in $DB_LIST; do BACKUP_DB_DIR=$BACKUP_DIR/${DB}_${DATE} [ ! -d $BACKUP_DB_DIR ] && mkdir -p $BACKUP_DB_DIR &>/dev/null TABLE_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "use $DB;show tables;" 2>/dev/null) for TABLE in $TABLE_LIST; do BACKUP_NAME=$BACKUP_DB_DIR/${TABLE}.sql if ! mysqldump -h$HOST -u$USER -p$PASS $DB $TABLE > $BACKUP_NAME 2>/dev/null; then echo "$BACKUP_NAME 备份失败!" fi done done

多循环的逻辑是为每个数据库创建一个以“库名+时间戳”命名的子目录,然后在这个目录下为每张表生成独立的SQL文件。这样做的好处是恢复时可以只恢复某一张表,做数据订正时效率极高。坏处也很明显——表数量多时会产生大量小文件,文件系统和传输都会变慢。实际使用中我一般配合find命令定期清理7天前的备份目录,否则磁盘会被小文件塞满。另外这两个脚本都用明文密码写在变量里,生产环境建议改用~/.my.cnf文件存放认证信息,避免ps进程列表里暴露密码。

3.3 Python与Bash的配合:企业微信告警和FTP客户端

备份脚本处理的是服务器内部事务,但故障最终要通知到人。合集里企业微信告警脚本用了Python实现,封装了获取token、上传素材、发送文本、发送图片几个方法。这部分的key在于复用:你不需要每次都重新走一遍企业微信API的鉴权流程,只需要实例化DLF类,传corpid和corpsecret进去,然后调send_text方法就能发告警。很多监控系统如Zabbix、Prometheus都可以通过webhook方式调用这类脚本,做到异常即告警。

FTP客户端也是同样的思路,用ftplib封装了一个FTPClient类,提供上传、下载、列目录、创建目录、删除文件、重命名、获取文件大小等常用操作。这里的细节处理值得学习:比如下载时如果传入的是目录路径,会自动和远程文件名拼接;获取文件大小时通过异常来判断是文件还是目录。这两个Python脚本展示了shell脚本合集向更复杂场景延伸的正确姿势:不是所有事情都适合用Bash硬写,遇到API调用、JSON处理、状态码判断,直接用Python可以少掉一半头发。

4. 日志处理与系统初始化:从发现状态到环境加固

4.1 Nginx日志按天切割:避免日志文件无限膨胀

Nginx日志如果不做切割,几个月下来能膨胀到几个GB,不仅影响磁盘,排查问题时打开文件也卡半天。脚本核心是用mv命令把当前日志重命名为带昨天日期的文件,再通过发送USR1信号让Nginx重新打开日志文件:

#!/bin/bash LOG_DIR=/usr/local/nginx/logs YESTERDAY_TIME=$(date -d "yesterday" +%F) LOG_MONTH_DIR=$LOG_DIR/$(date +"%Y-%m") LOG_FILE_LIST="default.access.log" for LOG_FILE in $LOG_FILE_LIST; do [ ! -d $LOG_MONTH_DIR ] && mkdir -p $LOG_MONTH_DIR mv $LOG_DIR/$LOG_FILE $LOG_MONTH_DIR/${LOG_FILE}_${YESTERDAY_TIME} done kill -USR1 $(cat /var/run/nginx.pid)

这里有个很容易被忽略的关键点:kill -USR1是Nginx优雅重开日志文件的机制。如果只做mv不发送USR1信号,Nginx会继续往被mv后的文件里写,日志就“断流”了。我记得第一次折腾这个脚本时没发信号,结果第二天一看所有日志都写进了同一个文件,切割完全失败。另外日志目录按月归档这个细节很贴心,比如2024年6月的日志都在/usr/local/nginx/logs/2024-06/目录下,归档和清理都很直观。

这个脚本建议用crontab每天凌晨0点执行一次。如果你用的是systemd环境,也可以做成一个timer单元来替代crontab,日志切割这事虽然小,但不处理会慢性要命。

4.2 Nginx访问日志分析:用awk四行命令看透流量

日志切割只是第一步,分析才是重头戏。合集里给了一个Nginx日志分析脚本,处理的是标准combined格式的日志。先定义好日志格式再逐个指标统计,这一段值得展开:

#!/bin/bash LOG_FILE=$1 echo "统计访问最多的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

这里awk '{a[$1]++}'是在以IP字段(第一列)为key做累加计数,END块里length(a)直接得到不重复IP的数量,相当于UV;然后for循环输出每个IP的访问次数,再通过sort按第二列数值倒序截取前10。第二个统计是“时间段访问最多的IP”,用字符串比较截取某个时间窗口内的记录——但这里注意日志里的时间字段带了方括号,比较时要用日志里实际的格式比如[01/Dec/2018:13:20:25,不同Nginx版本格式可能略有差异。

第三个统计是访问最多的页面,取第7列(也就是request字段包含的路径),加上if(a[v]>10)过滤条件排除低访问量页面;第四个统计状态码分布,把第7列和第9列拼接成“URL 状态码”的组合输出。整套分析没有用任何外部工具,纯awk实现,跑一次几秒就出结果。实际诊断服务器问题时,我一般先用它跑一遍,再针对性看某几个IP的详细请求,比直接打开日志文件翻效率高出很多。

4.3 系统初始化脚本:新服务器上线的一键加固

新机器上线最烦的不是装软件,而是那些基础项:时区不对导致日志时间差8小时、防火墙开着导致端口连不通、SELinux引发各种奇怪的权限问题、文件描述符限制让应用一压测就崩。这些重复劳动被整合成了初始化脚本,逻辑是按顺序处理每个配置项:

  • 软链接设置Asia/Shanghai时区,通过crontab定时用ntpdate做时间同步
  • 用sed修改/etc/selinux/config,把SELINUX从enforcing或permissive改为disabled
  • 判断系统版本是6还是7,分别用service或systemctl停防火墙并禁用开机启动
  • 在/etc/bashrc写入HISTTIMEFORMAT,让历史命令能显示执行时间和用户
  • 在/etc/profile写入export TMOUT=600,闲置超10分钟自动断开SSH
  • 把sshd_config的PermitRootLogin yes改成no,禁止root直接远程登录
  • 禁用crontab的邮件通知,避免系统每分钟收到一堆无用的本地邮件
  • 在limits.conf追加nofile软硬限制到65535
  • 往sysctl.conf写入tcp_syncookies、tcp_max_tw_buckets等几个常用的内核优化参数
  • 把swappiness设为0,优先使用物理内存减少交换分区

这个脚本的价值在于“一键”,而且每一步都是幂等操作。但用的时候要注意:设定root禁止远程登录前,务必确认你有一个可用的普通用户和sudo权限,否则脚本一跑完你自己也登不进去了——这种翻车事故我见过不止一次。另外内核参数里的数值是基于通用Web服务器场景给的,如果你的机器是数据库专用或高并发Nginx,要单独调优,不要盲目照抄。

4.4 进程与网卡监控:临时排查的趁手工具

合集里还有一类适合救急的脚本,比如查看网卡实时流量,利用/proc/net/dev文件来采样:

#!/bin/bash NIC=$1 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

/proc/net/dev里每个网卡给一行数据,第2列是累计接收字节数,第10列是累计发送字节数,脚本每隔1秒采样一次,做差值除以1024换算成KB/s。这个方法比用iftop要轻量,没有额外依赖,而且输出格式干净,可以直接重定向到文件做记录。另一个进程统计脚本通过遍历/proc下的数字目录读取每个进程的status文件,统计R(running)、S(sleeping)、T(stopped)、Z(zombie)四种状态的数量,如果发现僵尸进程就直接kill -9。

这两个脚本适合十分钟内快速开个终端盯着,不适合做长期采集。要长期保存监控数据,建议配crontab定时跑,把输出追加重定向到指定文件,脚本本身不需要做任何改动。需要注意的是,awk '$0~"'$NIC'"{print $2}'这种写法里变量$NIC的引用比较绕,不用双引号包住会匹配不到网卡名。

5. 避坑指南:脚本跑不通时优先排查这些点

5.1 日志切割后Nginx不再写新文件

运行日志切割脚本后发现新请求没有写入新的日志文件,访问量数据在日志里完全消失。

原因:mv操作之后没有给Nginx发送USR1信号,Nginx的文件句柄依然指向被重命名后的旧文件,内核里打开的还是那个inode。

解决:在脚本mv之后执行kill -USR1 $(cat /var/run/nginx.pid)让Nginx重新打开当前路径的日志文件。如果你不确定Nginx pid文件的位置,可以用ps -ef | grep nginx找到master进程的PID手动发信号。

5.2 mysqldump备份出现“Got error: 1044”权限报错

备份脚本执行过程中提示对某张表没有权限,但数据库列表明明能查出来。

原因:脚本用的backup用户只有show databases的全局权限,没有单库的SELECT和LOCK TABLES权限。mysqldump默认需要SELECT、SHOW VIEW、RELOAD等权限才能完整导出表结构和数据。

解决:给备份账号授权,重点确认usemysql库是否有SELECT权限,以及RELOAD权限是否开启。

5.3 防火墙脚本在CentOS 7上安静地失效

系统初始化脚本里关闭防火墙的部分执行了,但systemctl status firewalld显示还在活动状态。

原因:CentOS 7用firewalld替换了iptables服务,脚本先判断系统版本再执行对应命令的方式本身没问题,但有的初始化镜像里firewalld的unit文件被mask了,systemctl disable并不能真正停止服务。

解决:检查systemctl list-unit-files | grep firewalld的状态,如果显示masked,先执行systemctl unmask firewalld再停。另外生产环境不建议完全关闭防火墙,更稳妥的做法是开放需要的端口而不是禁用整个服务。

5.4 awk统计IP时把127.0.0.1也算进了访问TOP

用日志分析脚本统计访问最多的IP时,发现本机回环地址排在前面,干扰了真实访客数据的判断。

原因:Nginx配置里如果有server块监听了80端口且没限制来源,本机访问、监控系统的健康检查请求都会出现在access.log里,这些IP本身不构成攻击但会干扰统计。

解决:在awk统计命令后面加一个过滤条件,awk '$1!="127.0.0.1"{a[$1]++}'排除内网和回环地址。更严谨的做法是让监控系统的健康检查走一个单独的server块,静态返回200,不进入业务日志。

5.5 脚本循环里调ssh命令时tty分配导致输出错乱

批量SSH执行命令的脚本在多台机器上并行跑,输出结果有串行甚至命令回车符异常。

原因:ssh远程执行命令时默认会分配tty(-t参数),在循环里结合后台执行(&)时,tty的输出缓冲和多进程写到同一文件会产生交错内容。

解决:ssh命令加-o LogLevel=error -o StrictHostKeyChecking=no参数,去掉tty分配;多个子进程写同一个文件时,先各自写到单独临时文件再最后合并,或者在ssh命令前加</dev/null避免stdin干扰。

6. 二次开发:把279个脚本变成自己的运维工具箱

面对279个脚本,正确的使用方式不是全部跑一遍,而是挑出和自己环境匹配的部分做改造。我自己拿到这类合集后的标准流程分三步:搭一个测试环境把每个脚本先跑通,记录依赖路径和外部命令;然后按脚本的功能域重新组织目录,改成自己的统一风格;最后接入告警和定时任务,让它从“能跑”变成“在用”。

第一步搭建测试环境,建议用并夕夕版环境。开一台最小规格的虚拟机,装好Nginx和MySQL,把脚本里的路径、账号全部替换成测试值,然后手动执行,观察输出是否符合预期。这个阶段重点验证的是脚本里用到的命令是否都装了——比如mailx、ntpdate、sar、jstack,很多脚本就是因为少一个命令装到一半挂掉的。测试环境踩完坑,生产环境才敢直接上。

第二步是统一规范和参数化改造。我会把收集到的脚本梳理成自己熟悉的结构:init/目录放系统初始化,backup/目录放各种数据库备份,log/目录放日志处理,monitor/目录放监控脚本,alert/目录放告警通知。然后给每个脚本头部加上使用说明注释,把路径、账号、IP这些变量统一改成从配置文件里读取。比如初始化脚本里的内核参数,我会抽出一个sysctl.conf片段单独维护,而不是每次去改脚本主体。

第三步是接入crontab和告警。备份脚本、日志切割脚本、磁盘监控脚本这几类需要周期性执行的,统一写成自动化任务脚本。如果涉及多台服务器,可以再写一个deploy.sh,通过SSH批量把脚本分发到各台机器上执行。告警脚本可以接企业微信,通知内容里加上服务器名和异常指标。

关于脚本本身的质量,我的建议是拿合集当底料,但不要直接照搬到生产环境。所有判断失败的分支要补全,比如备份失败要写日志、发告警;所有明文的账号密码改成从独立配置文件读取,避免脚本被拉去审计时一脸尴尬。另外脚本语言风格尽量保持一致,变量命名、缩进、注释语言统一,这样后续维护成本最低。

如果你还愿意在这套脚本上继续投入,那可以从监控告警的闭环开始改。比如把DDoS防护脚本和告警结合起来,确认一个IP被封禁后立即通知运维;把磁盘监控脚本改造出分区维度,配合趋势图预测磁盘耗尽时间;把MySQL备份脚本的失败告警加上表级粒度。还可以把脚本的度量数据和个人经验沉淀下来,比如定期清理日志、定期做恢复演练——脚本只是工具,真正让系统稳定的是使用这些工具的人。

我自己现在收到任何脚本合集,都会先花半小时按这套流程过一遍,挑几个最贴合当前工作的脚本落地跑起来。有些脚本拿来就能用,有些脚本提供一个思路自己重写一遍,这个过程本身比脚本本身更有价值。希望这套279个脚本的工具包,能帮你省下那些重复劳动的时间,拿去陪陪家人,或者学点一直想学但没时间学的东西。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进