简介:279个开箱即用的shell脚本合集,面向Linux/Unix运维人员、系统管理员及正在学习DevOps与自动化的开发者,覆盖自动化运维中的高频实用场景。资源以PDF文档形式整理,文档内按场景收录了DDoS攻击自动屏蔽、Linux系统邮件告警、MySQL数据库单/多循环备份、Nginx访问日志按天切割与访问分析、网卡实时流量查看等常用脚本,并附有变量定义、条件判断、awk统计、iptables规则、mysqldump命令等关键注释与执行思路,便于理解、修改并直接部署。例如DDoS防御脚本通过tail、grep、awk统计异常IP并自动写入防火墙,MySQL备份脚本区分单表级与库级备份并记录错误日志。压缩包共1个文件,主要类型为PDF,大小约4.69MB,适合下载后离线查阅。目前已有154人学习,是希望快速积累Shell实战经验、完善服务器安全与备份机制的运维从业者值得收藏的参考合集。
1. 小白先别慌:Shell 脚本就是你的“自动值班员”
想象一下,你是一家公司的运维,每天重复做着同样的事:登录服务器看日志、备份数据库、检查磁盘空间、封禁可疑 IP。这套动作每天做一遍,枯燥不说,稍不留神还会漏掉某一步。我第一次接触 Shell 脚本时,脑子里只有一个念头:这些重复劳动,能不能让机器自己去做?答案就是 Shell 脚本。简单说,Shell 脚本就是把很多命令写进一个文本文件里,让计算机像读清单一样,一条接一条自动执行。它适用于所有 Linux/Unix 系统,也能跑在 Windows 的 WSL 或 Cygwin 环境里。对零基础新手来说,它不需要懂编程语言,只要你用过终端敲过命令,就已经拿到了入场券。这份《279个开箱即用的shell脚本》相当于一份现成的“命令食谱”,你不需要从零发明,只需要拿过来改改用。这篇入门文就带你搞清楚它是怎么回事、学了有什么用、第一个脚本怎么跑通。
2. 先搞懂一个底层概念:命令集合是怎么变成自动化工具的
2.1 终端里敲命令和脚本执行的区别是什么
你在终端里敲一条命令,机器就执行一次;敲十条,机器执行十次。这些操作本身没有记忆,关了终端就什么都没留下。而写一个 Shell 脚本,本质上是把这一串命令按顺序写进一个文本文件,让系统按行读取并执行。你可以把脚本理解成“给电脑的待办事项清单”。
比如你每天早上要做的三件事:备份数据库、切割 Nginx 日志、检查磁盘占用。如果手动做,大概要敲十几条命令,耗时几分钟。写成脚本后,一行命令搞定,全部自动跑完。这就是自动化最朴素的价值:把固定动作固化下来,让机器替人执行。
2.2 为什么说 279 个脚本里最值得先看的是“系统初始化”和“安全防护”
新手学习 Shell 脚本最大的难题不是语法,而是不知道“哪些场景真的需要脚本”。这份资料里 279 个现成脚本,覆盖了运维工作中最常碰到的几大类:系统初始化配置、安全攻击防护、数据库自动备份、日志切割与分析、服务器状态监控、文件批量操作、告警通知等。
对零基础新手来说,最推荐先看两类:一类是“服务器系统配置初始化脚本”,它把新服务器到手后要做的事(设置时区、关防火墙、禁用 root 远程登录、优化内核参数等)全部自动化,一次跑完;另一类是“Dos 攻击防范脚本”,它通过分析 Nginx 日志找出异常刷请求的 IP,并自动写入防火墙规则封禁掉。这两个脚本逻辑清晰、场景真实,看完你能直观感受到脚本带来的收益:别人手动配置半天的活儿,脚本几秒完成,这比任何理论讲解都更有说服力。
2.3 第一个例子:用三行脚本感受“清单被执行”的过程
我们从一个最简单的例子开始,它不需要安装任何额外软件,只要你有 Linux 环境(或者 Windows 上的 WSL)就行。
#!/bin/bash # 这是我的第一个shell脚本:输出一行问候,再显示当前目录 echo "你好,Shell 脚本!" pwd把这个文件保存为hello.sh(用vim hello.sh或记事本都行),然后给它加上执行权限并运行:
chmod +x hello.sh ./hello.sh这里有三件事需要理解。第一行的#!/bin/bash叫“释伴行”,它告诉系统“用哪个解释器来执行这个文件”,相当于文件的使用说明书。echo是输出文本的命令,pwd是显示当前所在目录的命令。第 7 行的chmod +x是给文件赋予“可执行”权限,没有这一步会提示Permission denied,这是新手最容易碰到的坑。
运行结果会是两行:一行中文问候,一行你的当前目录路径。到这里你其实已经跑通了第一个脚本。它虽然简单,但骨架已经完整:文件头、命令、执行权限、运行,这四要素在之后的任何脚本里都会反复出现。
3. 那些“开箱即用”的脚本到底做了什么:拆解两个核心脚本
3.1 安全防护类:自动屏蔽攻击 IP 的脚本拆解
先看一个实际场景。你的网站跑在 Nginx 上,某个 IP 在短时间内疯狂请求页面,消耗服务器资源,这就是常见的 Dos 攻击(拒绝服务攻击)。手动处理需要:登录服务器、看日志、数请求次数、加防火墙规则,整套流程至少五分钟。下面的脚本把这个过程压缩成了每五分钟自动执行一次:
#!/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逐段解释。DATE=$(date +%d/%b/%Y:%H:%M)的作用是拿到当前的小时时间,比如05/Jan/2025:14:30,用它来筛出“这一小时内”的日志。LOG_FILE指定 Nginx 日志的存放路径,如果你的日志路径不同,这行是必须改的第一个地方。第三行比较长,它的逻辑是:取日志最后 5000 行,筛出当前小时的记录,再用awk统计每个 IP 出现的次数,只输出访问次数超过 10 次的 IP。
for IP in $ABNORMAL_IP的意思是:把上一步筛出的异常 IP 逐个拿出来处理。循环体里先检查这个 IP 是否已经在防火墙规则里(iptables -vnL |grep -c "$IP"),如果有就跳过,没有则执行iptables -I INPUT -s $IP -j DROP把该 IP 的所有流量丢弃,最后把封禁记录追加到日志文件。
这个脚本最值得学习的是“检查再操作”的思维:先判断是否已封禁,避免重复添加规则。很多新手写脚本不考虑幂等性,跑一次加一条规则,跑十次加十条重复规则,这是逻辑上的常见问题。
3.2 系统初始化类:新服务器到手后一键配置脚本拆解
另一类高频场景是初始化新服务器。你刚买一台云主机,它默认开着防火墙、允许 root 远程登录、没有时间同步、内核参数不是最优的。手动配置这些项目,新手至少需要两个小时,而且很容易漏项。下方的初始化脚本把十几步操作串成一条流水线:
#!/bin/bash # 设置时区并同步时间 ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime if ! crontab -l |grep ntpdate &>/dev/null ; then (echo "* 1 * * * ntpdate time.windows.com >/dev/null 2>&1";crontab -l) |crontab fi # 禁用SELinux sed -i '/SELINUX/{s/permissive/disabled/}' /etc/selinux/config # 关闭防火墙 if egrep "7.[0-9]" /etc/redhat-release &>/dev/null; then systemctl stop firewalld systemctl disable firewalld fi # 历史命令显示操作时间 if ! grep HISTTIMEFORMAT /etc/bashrc; then echo 'export HISTTIMEFORMAT="%F %T `whoami` "' >> /etc/bashrc fi # 禁止root远程登录 sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config这里包含了几种常用语法。ln -s创建软链接,把系统时区指向上海,这样date命令显示的就是北京时间。if ! crontab -l |grep ntpdate的意思是“如果定时任务里没有 ntpdate,就追加一条”,这个写法避免了重复添加。sed -i是文本替换的核心工具,比如把#PermitRootLogin yes替换成PermitRootLogin no,实现禁止 root 远程登录。最后的systemctl是 CentOS 7 系列的管理命令,而脚本同时兼容 CentOS 6(用service命令),这种“同一逻辑、多版本兼容”的写法在成熟脚本里非常常见。
这个脚本的参考价值在于:它演示了脚本如何与系统配置文件打交道。配置类任务本质是“找到配置文件、定位要改的行、精确替换”,sed和grep是这里的两大主角。新手不需要记住每个参数,先看懂这个流程,后面自然能举一反三。
3.3 学完这两段脚本,你应该收获什么
读完这两个脚本,你已经开始理解运维脚本的真正逻辑了:安全脚本的核心是“分析日志 → 提取目标 → 执行封禁”,初始化脚本的核心是“检查当前状态 → 执行修改 → 避免重复操作”。这两个套路几乎可以套用到后面大部分脚本里。其他脚本如 MySQL 备份、日志切割,本质也是循环 + 判断 + 执行命令的组合。
4. 实战最常见场景:日志切割、数据库备份、并发监控
4.1 Nginx 日志按天切割:为什么不能直接删旧日志
服务器跑久了,Nginx 访问日志会变得巨大,直接打开都很卡,更别说分析。按天切割的意思是:每天凌晨把昨天的日志文件改名归档,让 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)先看YESTERDAY_TIME=$(date -d "yesterday" +%F),date的-d参数允许你取相对日期,这里是取昨天,+%F是格式化为年-月-日,比如2025-01-06。LOG_MONTH_DIR是生成按月份归档的目录,也就是说 2025 年 1 月的日志都放进2025-01目录。循环里先判断目录是否存在,不存在就建立,然后把旧日志移到归档目录并加上日期后缀。
最后一行kill -USR1是个关键点:直接改名后 Nginx 还会继续往旧文件名里写内容,必须用kill -USR1让 Nginx 重新打开日志文件,实现“平稳过渡”。这是新手最容易漏掉的细节,漏掉的话日志还会写进旧的文件句柄里。配合 crontab 每天凌晨执行一次这个脚本,日志管理就完全自动化了。这个脚本里你学到的不只是mv命令,更是“文件操作后需要通知对应服务”的系统级思维。
4.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 doneDB_LIST这一行很值得细看。mysql -e "show databases;"是执行 SQL 并直接返回结果,-s是跳过表头,egrep -v是排除系统自带库(information_schema、mysql、performance_schema、sys),因为这些库不是业务数据,备份它们没有意义还浪费空间。mysqldump -B $DB会导出整个库的结构和数据,输出重定向到了以库名和日期命名的 SQL 文件。失败时输出“备份失败”到控制台,方便排查。
多循环版本的区别在于粒度:先循环数据库,再循环每个库里的所有表,每个表的备份单独放一个文件。这样做的优点是可以针对单表做恢复,不用整库回滚;代价是文件数量多、耗时更长。选择原则很简单:数据量小、追求简单,用单循环;数据量大、需要单表恢复,用多循环。你实际使用时还要考虑加crontab定时任务,同时定期检查备份文件大小是否正常——备份脚本本身就是一道保障,但如果备份文件一直是 0 字节,等于没有备份,这也是需要定期验证的原因。
4.3 并发监控:多台服务器同时收集信息
当监控对象从一台变成几十台上百台,顺序执行会慢得让人崩溃。下面的脚本演示了并发思想,从多台机器同时获取hostname并统计哪台响应最快:
#!/bin/bash ALL_HOSTS=(IP地址 IP地址) for host in ${ALL_HOSTS[*]} do { start_time=$(date +'%s') ssh $host "hostname" &>/dev/null sleep 2 stop_time=$(date +'%s') time_consuming=$((stop_time-start_time)) echo "$host: $time_consuming" >>hostname.txt }& done wait host=$(sort -n -k 2 hostname.txt | head -1 | awk -F':' '{print $1}') ssh $host "top -b -n 1"核心是&符号和wait命令的组合。&把循环体放到后台执行,让多个 SSH 请求同时发起,而不是一个等一个。wait等待所有后台任务完成后再继续往下走。最后把收集到的耗时数据排序,找出最短的那个主机,再登录它执行top看 CPU 信息。这个思路在生产环境中常被用来批量巡检服务器状态,你后面写批量操作脚本时,&会是提升效率的重要帮手。
5. 新手避坑指南:Shell 脚本最容易踩的 5 个坑
5.1 脚本在 Windows 上编辑后,运行报错“/bin/bash^M”
现象:脚本明明没写错,一运行就提示/bin/bash^M: bad interpreter,或者报一堆乱码错误。
原因:Windows 记事本保存文件时,每行结尾带有\r\n(回车 + 换行),而 Linux 只认\n,多出来的\r就变成了^M这个隐藏字符。这是把 Windows 当编辑器写脚本最典型的翻车现场。
解决:在 Linux 里用vim打开文件,执行:set ff=unix然后保存;或者直接用sed -i 's/\r$//' 你的脚本.sh把它洗干净。习惯上建议:写脚本就在 Linux 里写,或者用 VSCode 并确保右下角行尾符显示为LF。
5.2 忘记加执行权限,提示 Permission denied
现象:脚本运行后直接报Permission denied,但内容完全没问题。
原因:新手不知道 Linux 里文本文件默认没有“可执行”权限,直接./xxx.sh当然会被拒绝。在 Windows 时代没有这种观念,所以它是新手最容易卡住的一个环节。
解决:先chmod +x 脚本名.sh再运行,好习惯是把授权和运行连成一条命令:chmod +x xxx.sh && ./xxx.sh。如果你非要以bash xxx.sh的方式运行,不需要授权也能跑,但日常推荐直接执行,因为你能顺便验证调用逻辑。
5.3 直接执行杀进程命令时误杀自己
现象:用ps -ef | grep keyword查找进程时,结果里带着一条grep keyword自己的进程。如果后续脚本对这个结果执行kill,会把自己也结束掉。
原因:grep匹配的时候,自己的命令行里含有这个关键词,所以也被列进了结果。
解决:脚本里常见写法是ps -ef | grep 'inceptor' | grep -v grep | awk '{print $2}',grep -v grep就是过滤掉带 grep 的那一行。最大的教训是:在你输出的 PID 列表里,先人工检查一遍再执行删除操作。生产环境里误杀进程的成本往往很高。
5.4 脚本里路径写死,换台服务器就报错
现象:日志切割脚本在 A 机器上正常运行,复制到 B 机器就提示“文件不存在”或目录创建失败。
原因:LOG_DIR=/usr/local/nginx/logs、BACKUP_DIR=/data/db_backup这类路径是编写的环境里预设的,换到另一台机器,可能目录结构完全不一样。
解决:拿到一个现成脚本,第一步就是检查所有路径相关的变量。我的建议是把路径抽出来放在脚本头部(已经有很多脚本这样做了),你只需要改一处即可。另外,在脚本开头加一句mkdir -p确保目标目录存在,可以减少很多麻烦。涉及系统环境差异的还有防火墙版本(CentOS 6 vs CentOS 7)、包管理器(yum vs apt),碰到问题先确认系统版本,再回头看命令。
5.5 日志路径和文件名写错,安全脚本把无辜 IP 封了
现象:用日志分析脚本封了一批 IP,结果发现里面有自己的 IP,管理员被关在服务器外面。
原因:日志文件的路径、日志格式、时间格式三个环节任何一个不匹配,统计出来的“异常 IP”就会有偏差。比如自定义日志格式和awk里取第几个字段没对应上。
解决:在正式大批量封禁前,先对一小段日志跑一次统计命令,把输出的 IP 列表人工扫一眼,确认没有关键地址再放开执行。脚本里加白名单机制也是成熟的做法(排除内网 IP 段),这属于进阶用法,但你至少要有这个意识:脚本自动化程度越高,运行前确认边界就越是必须的。从那以后我每次跑安全类脚本都强制走一遍“先打印结果、再执行操作”的流程。
6. 下一步怎么学:从读懂脚本到改出自己的脚本
6.1 按顺序读完这些脚本,你就跨过了新手门槛
拿到这份 279 个脚本的资源,不要从头到尾硬读,那样坚持不了几天。我的建议是按三条线走。第一条线是基础命令线,先熟练掌握grep、awk、sed、find、xargs这五个命令的常见用法,它们大约出现在 80% 的运维脚本里。第二条线是场景线,优先挑你工作中已经遇到的问题来读:比如服务器老是被扫描,就去读安全防护类;比如 Nginx 日志越来越大,就去读日志切割类。带着问题读脚本的效率远高于无目的浏览。第三条线是改写线,把脚本里你不理解的参数查明白后,把路径、阈值、告警接收人改成自己的环境,顺势就完成了“读懂”到“能改”的过渡。
6.2 推荐的一个小练习:把一段重复操作写成脚本
练习目标很简单,从你的日常操作里找你最常敲的三条命令,把它们写成一个脚本。比如你经常要进一个项目目录、开虚拟环境、启动服务,可以写:
#!/bin/bash # 日常开发启动脚本:一键进入工作目录并启动服务 cd /home/me/project/myapp source venv/bin/activate python manage.py runserver 0.0.0.0:8000保存为dev.sh,授权后运行,你从此告别每次手动敲三行命令。这个练习虽然简单,但意义重大:你开始把脚本用于解决自己的问题,而不是照着别人的需求背语法。接下来再进阶一步,试着在上面加入参数,比如允许传入端口号:
#!/bin/bash PORT=${1:-8000} cd /home/me/project/myapp source venv/bin/activate python manage.py runserver 0.0.0.0:$PORT${1:-8000}的意思是:运行时第一个参数如果有值就用它,没有就用 8000。这样你可以./dev.sh 8080启动到其他端口。这个写法在高级脚本里到处都是,理解了它,你就能看懂大段脚本中“默认值”的处理逻辑。
6.3 长期来看值得建立的两个习惯
第一个习惯是做实验要留后路。改系统配置文件前,先备份原始文件(cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak),脚本里涉及sed -i的地方同理。后悔药不难准备,但忘掉一次可能就得花很久恢复。第二个习惯是刻意练习“读错误信息”。新手一看到满屏报错就慌,其实终端里几乎所有的报错都指出了具体行号和原因,先读第一行,再读最后一行,中间内容多数是连带输出。遇到不认识的关键词,直接复制进搜索引擎,绝大多数情况能找到答案。
我带过不少完全零基础的人入门 Shell,发现真正决定学习结果的不是天赋,而是有没有立刻动手跑通第一个例子。你不需要一次性搞懂 279 个脚本,把那句echo "你好,Shell 脚本!"跑通,你就已经比昨天进了一步。这份资源的意义不在“读”,而在“用”:用到自己环境里,解决自己的问题,才算真正完成入门。希望这一篇能帮你把第一步走踏实。
本文还有配套的精品资源,点击获取