☰
279个开箱即用Shell脚本:从落地、选型到生产级改造避坑指南
2026/10/12 20:07:35 网站建设 项目流程

简介:汇总279个可直接投入使用的Shell脚本应用集,覆盖DDoS攻击IP自动屏蔽、Linux系统邮件告警、MySQL数据库单/多循环备份、Nginx访问日志按天切割与深度分析、网卡实时流量监控等高频运维场景。脚本逻辑清晰、关键命令注释完整,适合Linux/Unix系统管理员、运维工程师及希望提升自动化能力的初中级学习者参考,可结合实际业务需求修改后部署。资源包内共1个PDF文档,体积4.69MB,便于快速浏览、检索与离线学习;当前已有154人学习下载。内容不仅有现成脚本代码,还梳理了日期获取、日志分析、iptables策略、mysqldump备份、cron定时任务等核心技术点,帮助读者理解脚本背后的设计思路与排错途径。对于需要快速构建服务器安全防护、数据库灾备和日志管理体系的团队,这份资料具备较高实用价值。

1. 279个开箱即用的shell脚本,治好的是“重复劳动”焦虑,不是“复杂问题”执念

第一次拿到“279个开箱即用的shell脚本”压缩包时,我的第一反应是“这么多,八成有摆设”。翻完关键脚本后发现,它的价值不在单个脚本多聪明,而在于把巡检、日志、备份、网络检查这些最高频的运维场景统一成可以直接跑的形态。2024年新版脚本风格更干净,变量、函数、退出码的约定更一致,这对批量投入使用的人来说反而最值钱。

这套东西适合日常维护几十台服务器的运维、刚接手机器又不想从零养脚本库的开发者,也适合交付时快速凑齐基础检查项的人。它解决的是重复劳动,不是复杂问题。下面按“怎么落地、怎么选、怎么改、坑在哪”的顺序,把这套脚本真正用起来。

2. 压缩包到手怎么落地:目录规划、环境准备和首次运行

拿到279个脚本的压缩包之后,第一件要做的事不是立刻翻代码,而是先把目录结构立起来。脚本集合最大的隐患就是目录乱,脚本放在顶层、配置文件散落各处、日志不知道写到哪里,一旦跑起来根本没法维护。我一般会首先在服务器上建一个独立目录,比如~/ops/shell-lib,把整个集合按“可执行脚本、公共函数、配置文件、日志、备份产物”拆成五块。

2.1 拿到手先定位:先看目录树和说明文档

先把压缩包解开,然后用tree -L 2看结构,第一时间确定三件事:脚本是不是按功能分子目录了、有没有公共函数文件、有没有内置的说明文档。很多脚本集合表面有279个文件,实际有效脚本只有两百多,剩下的是配置文件、空目录、说明文档,甚至有几个是同一个脚本的旧版本。

mkdir -p ~/ops/shell-lib cd ~/ops/shell-lib # 解压指令要和你实际拿到的包名一致 tar xzf shell-scripts-2024.tar.gz # 看两层目录,先摸清结构再动手 find . -maxdepth 2 -type f | head -50

这段代码的作用是先把环境立起来。mkdir -p保证目录不存在时自动创建,后面所有脚本都能在这个公共目录里启动。find加上maxdepth 2是为了先看前两层,避免一次性输出太多文件反而看不清结构。解压之后我建议把包里的说明文档先翻一遍,重点看作者声明的依赖项、Linux发行版兼容性、有没有说明默认安装路径,这些信息比脚本本身更能决定你能不能在一小时内跑通。

2.2 环境准备:先确认本地有没有这些默认依赖

279个脚本不可能都只用原生的bash。凡是涉及网络、磁盘、数据库、文本处理的脚本,多少都会依赖外部命令,最常见的是curl、grep、awk、sed、gzip、df、mysqldump、jq。跑全套之前,我建议先做一次依赖盘点,缺什么补什么,避免脚本跑到一半才报“command not found”。

# 一键检查常用依赖是否存在 for cmd in bash curl grep awk sed gzip df jq mysql mysqldump bc getopt; do if command -v "$cmd" >/dev/null 2>&1; then echo "[OK] $cmd" else echo "[MISSING] $cmd" fi done

这段代码的意义不是挨个执行which,而是用command -v做一次快速扫描。command -v返回0表示命令存在,非0表示缺失,比which更可靠,因为which在某些精简系统里本身可能就不存在。输出里凡是出现[MISSING]的,就是你在跑对应脚本之前必须先处理的。比如jq缺失,JSON解析类的脚本就跑不了;mysql缺失,数据库备份脚本就会在执行时直接退出。

2.3 把 bin 目录加进 PATH,让脚本可以被直接调用

不把脚本加进 PATH 的后果是,你每次都要bash /完整/路径/脚本.sh,这非常累,而且脚本里的人相对路径一旦写错就会翻车。常见做法是在~/.bashrc里增加环境变量,把脚本的核心目录固定下来,再把可执行脚本所在的 bin 目录加进 PATH。

cat >> ~/.bashrc <<'EOF' # shell脚本库环境变量 export OPS_HOME="$HOME/ops/shell-lib" export OPS_CONF="$OPS_HOME/conf" export OPS_LOG="$OPS_HOME/logs" export PATH="$OPS_HOME/bin:$PATH" EOF source ~/.bashrc # 验证是否能直接找到脚本 command -v disk_check || echo "还没找到,检查 PATH 配置"

这里用<<'EOF'而不是<<EOF是有意的,带引号的 EOF 能防止$HOME、$OPS_HOME在追加时被展开,确保变量是写进文件里、而不是写成固定的当前目录值。source之后,新开的终端也会生效。PATH 加在靠前位置,是防止系统里同名命令覆盖脚本库。

2.4 跑通第一个脚本:先选一个副作用最小的脚本验证环境

想验证整个环境是否正常,最快的办法是跑一个只读类脚本,比如磁盘空间检查或系统信息收集脚本。这种脚本没有删除操作、不写外部文件,跑挂了也不影响系统。以磁盘检查脚本为例,你只需要传一个阈值参数进去:

# 阈值设成90,意思就是超过90%才告警 bash bin/disk_check.sh 90 echo "退出码:$?"

跑完你会发现,脚本输出可能只有一行,也可能有格式化表格,更重要的是退出码。很多脚本都会约定0为正常、非0为异常。在第一次跑通之后,我建议你观察一下它的输出格式:是纯文本、还是带颜色、还是能输出 CSV。这一步看起来不起眼,但后面你要接告警或自动化平台时,输出格式决定了你要不要加一层解析。

3. 279个脚本按场景怎么选:巡检、日志、备份、网络四类先看哪几个

脚本集合一多,最容易犯的错是把时间花在“把所有脚本都读一遍”上。我的建议是反过来,先确定你自己手头最痛的场景,再按场景去翻对应脚本。绝大多数合集里的脚本都能归到四类:系统巡检、日志处理、数据库备份、网络连通性检查。每一类的考察重点不一样,下面分别说。

3.1 系统巡检类:先看指标采集范围,再看输出格式

系统巡检类脚本通常是这个合集里数量最多的一类,涵盖CPU负载、内存占用、磁盘容量、进程数、登录失败次数等等。挑选时我只看两点:第一是指标采集是否用对了命令,第二是结果是否结构化。

# 一个典型的巡检脚本骨架:采集磁盘使用率并输出 CSV #!/usr/bin/env bash set -Eeuo pipefail echo "filesystem,use_percent,mount_point" df -h | awk 'NR>1 { gsub("%", "", $5); print $1","$5","$6 }'

这段代码展示了巡检脚本的通用套路。set -Eeuo pipefail让脚本在遇到未定义变量、管道失败时立刻退出,避免错误被吞掉。df -h输出第一行是标题,NR>1跳过标题行,gsub把百分比后面的%去掉,最后拼成CSV。你拿到巡检脚本时,重点看有没有类似的“可解析输出”设计。如果一个巡检脚本只是打印一堆字符串没有分隔符,那它更适合人看,不适合接自动化平台。

3.2 日志处理类:切割、归档、统计三件事,边界条件完全不一样

日志脚本在279个集合理通常也占不小比例。按天切割是最常见的需求。挑日志脚本时要特别留意三件事:文件名后缀怎么生成、是否跳过正在写的内容、保留天数由什么参数控制。

# 日志切割脚本:按天归档,并按保留天数清理旧日志 #!/usr/bin/env bash set -Eeuo pipefail LOG_DIR="${1:-/var/log/myapp}" KEEP_DAYS="${2:-7}" if [ ! -d "$LOG_DIR" ]; then echo "[ERROR] 目录不存在: $LOG_DIR" >&2 exit 2 fi # 将 *.log 原地压缩为 *.log.20240101.gz find "$LOG_DIR" -maxdepth 1 -type f -name "*.log" -print0 | while IFS= read -r -d '' f; do gzip -S ".$(date +%Y%m%d).gz" "$f" done # 找到超过保留天数的 .gz 文件并删除 find "$LOG_DIR" -maxdepth 1 -type f -name "*.gz" -mtime +"$KEEP_DAYS" -delete

这段代码把切割和清理分成两步。参数化设计让路径和保留天数可以在调用时传,${1:-默认值}的写法保证不传参也不会直接报错。-print0配合read -r -d ''是为了处理文件名里有空格的情况,这一步在日志目录里特别重要,很多日志文件名都带空格或特殊字符。gzip -S指定压缩文件后缀,-mtime +$KEEP_DAYS表示只看修改时间超过N天的文件。

你拿到合集里的日志脚本时,先确认它用的是-print0还是普通的-exec。如果是普通写法且没做过滤,遇到带空格的文件名大概率会翻车。

3.3 数据库备份类:先看备份用的命令、压缩方式、恢复脚本有没有配齐

数据库备份脚本是风险最高的一类,因为它的运行结果直接影响可用性。这类脚本我建议你只信“能恢复的备份”,也就是备份完一定要有办法验证。选型时先看它用的是mysqldump、pg_dump还是文件系统快照方式,再看有没有配套的恢复脚本。

# MySQL 备份脚本骨架:按库导出并压缩 #!/usr/bin/env bash set -Eeuo pipefail DB_USER="${DB_USER:-backup_user}" DB_PASS="${DB_PASS:-}" DB_NAME="${1:-}" BACKUP_DIR="${2:-/var/backups/mysql}" if [ -z "$DB_NAME" ]; then echo "用法: $0 <数据库名> [备份目录]" >&2 exit 2 fi STAMP=$(date +%Y%m%d_%H%M%S) mkdir -p "$BACKUP_DIR" mysqldump --single-transaction -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" | gzip > "$BACKUP_DIR/${DB_NAME}_${STAMP}.sql.gz" echo "备份完成: $BACKUP_DIR/${DB_NAME}_${STAMP}.sql.gz"

数据库脚本最重要的参数是--single-transaction,它保证备份期间不锁表,在线备份时尤其关键。用户名和密码通过环境变量传入,而不是写死在脚本里,这是接手任何备份脚本时最应该先改的地方。备份完成后,我会额外跑一次gzip -t来验证压缩包完整性,再决定要不要保留这个脚本作为日常任务。

3.4 网络与连通性检查:以退出码和超时为准,别只看输出

网络类脚本和其他脚本最大的不同是,它的执行结果受到外部环境干扰,丢包、超时、DNS解析失败都可能让输出变得不可信。挑这类脚本时,重点看有没有设置合理超时,以及是否以退出码作为判断依据。

# 连通性检查:带超时并输出结构化结果 #!/usr/bin/env bash set -Eeuo pipefail TARGET="${1:-8.8.8.8}" COUNT="${2:-3}" TIMEOUT="${3:-2}" if ping -c "$COUNT" -W "$TIMEOUT" "$TARGET" >/dev/null 2>&1; then echo "reachable" exit 0 else echo "unreachable" exit 1 fi

这段代码把输出和退出码绑在一起,正常时输出reachable并返回0,失败时输出unreachable并返回1。-W是超时秒数,-c是发包数量。注意ping的参数在 Linux 和 macOS 上不一样,macOS 用的是-t,你如果脚本库里混用了这两个参数,到了另一台机器上就会直接报错。这类脚本还有一点要注意,就是不要把 ICMP 连通性和服务可用性混为一谈,端口通不通是另一层问题。

4. 挑三个脚本做生产级改造:参数化、配置化、退出码一个都不能少

279个脚本里真正能“开箱即用”的估计只有一半多,另外一半要么是示例、要么是某个特定环境的写法。我的经验是,与其把这279个都用一遍,不如挑三个最常用的改造到能直接进生产。改造的目标很简单:参数能传、配置能改、退出码能信。

4.1 日志切割脚本改造:把路径和保留天数抽成参数

先改造日志切割脚本。原始脚本很可能把路径写死在文件里,比如LOG_DIR="/var/log/nginx"。这种写死的问题是你复制到新机器上就必须打开文件改,很容易改错。改造后应该支持两个参数:日志目录和保留天数。

#!/usr/bin/env bash # 按天切割日志,保留 N 天 # 用法: log_rotate.sh <日志目录> [保留天数] set -Eeuo pipefail LOG_DIR="${1:?必须指定日志目录}" KEEP_DAYS="${2:-7}" if [ ! -d "$LOG_DIR" ]; then echo "[ERROR] 目录不存在: $LOG_DIR" >&2 exit 2 fi # 第一步:压缩现有 *.log find "$LOG_DIR" -maxdepth 1 -type f -name "*.log" -print0 | while IFS= read -r -d '' f; do gzip -S ".$(date +%Y%m%d).gz" "$f" done # 第二步:清理超过保留天数的压缩包 # 注意:-mtime 的数值是“超过 N 天”,保守起见可以加 1 find "$LOG_DIR" -maxdepth 1 -type f -name "*.gz" -mtime "+$((KEEP_DAYS+1))" -delete echo "[OK] $LOG_DIR 切割完成,保留 $KEEP_DAYS 天"

这次改造有三个关键变化。第一个是${1:?必须指定日志目录},这个写法会在参数为空时报错并退出,避免后续所有命令拿空值去执行。第二个是KEEP_DAYS的默认值7天,调用者不传也能跑。第三个是删除条件用了+$((KEEP_DAYS+1)),也就是保留N天多一点,防止刚切割完的文件因为时间边界被误删。实践中最容易翻车的就是这个保留天数边界,建议按“多留一天”来改删文件条件。

4.2 磁盘告警脚本改造:阈值参数化,告警通道和检测逻辑分离

磁盘告警脚本是另一个高频改造对象。最初的版本往往只负责“检测加打印”,能不能真正告警取决于你把它接到哪里。我习惯把告警动作单独拆出去,检测脚本只负责判断和输出,告警逻辑通过回调函数或环境变量来指定。

#!/usr/bin/env bash # 磁盘使用率告警,阈值作为参数 # 用法: disk_alert.sh [阈值] [文件系统] set -Eeuo pipefail THRESHOLD="${1:-80}" FILESYSTEM="${2:-/}" USAGE=$(df -h "$FILESYSTEM" | awk 'NR==2 {gsub("%","",$5); print $5}') if [ "$USAGE" -ge "$THRESHOLD" ]; then echo "[ALERT] $FILESYSTEM 使用率 ${USAGE}% 超过阈值 ${THRESHOLD}%" # 告警通道由环境变量决定,不在脚本里写死 # 调用侧示例: ALERT_CMD="curl -s -X POST http://alert-server/api" if [ -n "${ALERT_CMD:-}" ]; then $ALERT_CMD "$FILESYSTEM $USAGE" fi exit 1 fi echo "[OK] $FILESYSTEM 使用率 ${USAGE}%" exit 0

改造的重点是把“告警方式”从脚本里摘出去。你在这台机器上可能想发HTTP请求到告警平台,在另一台机器上只想写日志,如果脚本写死了告警方式,就很难复用。用ALERT_CMD环境变量把告警命令交给调用者定义,脚本本身只做检测和判断。这里没有给$ALERT_CMD加引号,是刻意让 shell 按空格分词,把命令和参数拆开;这种写法对安全边界有要求,所以注释里写清楚了调用侧负责定义可信命令。

4.3 批量执行器改造:处理空行、注释、引号,防止命令被拆碎

批量执行器的作用是从一个主机列表文件里逐行读服务器,然后统一执行命令。这种脚本看起来简单,但最容易出问题的是文件读取逻辑。没有经验的写法是for i in $(cat list),一旦列表里有空格或空行,处理逻辑就会崩。更稳妥的是用while read配合IFS=。

#!/usr/bin/env bash # 批量执行器:从文件逐行读取主机并执行命令 # 用法: batch_exec.sh 主机列表.txt [命令] set -Eeuo pipefail HOSTS_FILE="${1:?必须指定主机列表文件}" CMD="${2:-uptime}" if [ ! -f "$HOSTS_FILE" ]; then echo "[ERROR] 文件不存在: $HOSTS_FILE" >&2 exit 2 fi # 逐行读取,跳过空行与 # 开头的注释行 while IFS= read -r host || [ -n "$host" ]; do case "$host" in ""|\#*) continue ;; esac echo "======== $host ========" ssh -o ConnectTimeout=5 -o BatchMode=yes "$host" "$CMD" done < "$HOSTS_FILE"

这段代码里有三个关键点。第一,IFS=禁止行内字段分割,保证一行内容完整进入host变量,不会被空格切开。第二,|| [ -n "$host" ]处理最后一行没有换行符的情况,避免最后一个主机被漏掉,这是一个非常隐蔽的问题。第三,用case匹配空行和#开头的注释行,让主机列表文件可以直接带注释,方便维护。-o BatchMode=yes让 ssh 在无法交互时直接失败而不是挂住,配合ConnectTimeout=5能避免批量执行卡死。

5. 生产环境跑这279个脚本:5类避坑与排查记录

把脚本从“能跑”变成“敢在凌晨三点让它自己跑”,要过的坑比想象中多。下面这几类是我在多个环境里反复踩过的,按出现频率从高到低排。

5.1 现象:脚本报“No such file or directory”,但文件明明在

这是 Windows 编辑脚本后最常见的翻车现场。你从 Windows 上传到 Linux,脚本第一行是#!/usr/bin/env bash,执行时却报No such file or directory,或者提示/usr/bin/env bash^M。原因很简单:文件是 CRLF 换行,bash 解释器把回车符当成了命令或路径的一部分。

解决方法是把所有脚本批量去掉\r:

# 批量把 CRLF 转成 LF find . -name "*.sh" -exec sed -i 's/\r$//' {} \; # 验证是否还有残留回车 cat -A bin/disk_check.sh | grep -n '\^M' || echo "没有残留 ^M"

绝大多数脚本集合下载后是压缩包,不会强制转行。如果你在 Windows 上用编辑器改过脚本,改完一定记得转回 LF。sed -i 's/\r$//'只去掉行尾回车,不影响文件内容里的其他字符。cat -A是验证用的重要工具,^M就是回车符的显示形态。

5.2 现象:中文输出乱码,脚本里写的中文注释全变成“锟斤拷”

某些脚本里带中文提示或日志说明,运行环境语言环境不一样就会出现乱码。原因不是脚本本身坏了,而是终端或机器的 locale 与脚本编码不匹配。

解决方向有两个。一是统一把脚本编码设成 UTF-8,二是运行脚本前导出语言环境:

# 在 /etc/profile.d/ 或 ~/.bashrc 里固定语言环境 export LC_ALL=C.UTF-8 export LANG=C.UTF-8

注意不要把LC_ALL随便设成en_US.UTF-8,因为服务器上不一定装了对应的 locale 包,硬设反而会在某些命令里报错。C.UTF-8几乎每个发行版都有。你接手脚本库时可以先跑file 脚本名看编码,如果是ISO-8859或GBK,再考虑要不要转换。

5.3 现象:脚本依赖的命令本机没有,跑一半就退出

279个脚本里会有不少依赖外部命令,最典型的是mysql、jq、bc、getopt。内网机器不一定允许随便装包。我见过有人在生产机器上因为没有jq而临时把 JSON 解析脚本改成grep + sed,这种做法短期可行但不好维护。

更好的做法是先做依赖检查和降级方案:

# 依赖命令缺失时的优雅退出 if ! command -v jq >/dev/null 2>&1; then echo "[WARN] jq 未安装,跳过 JSON 解析功能" >&2 exit 3 fi

这类脚本最关键的是“提前退出”而不是“跑到一半崩掉”。退出码用3这类业务码,而不是127的 command not found,方便上层平台区分原因。如果你确实要跑一个必须依赖某命令的脚本,那就老老实实装依赖,不要用 sed 硬解析 JSON,那会让后续维护成本失控。

5.4 现象:脚本里有 rm 删除,不知道会删到哪

脚本合集里肯定有一批带rm -rf或find ... -delete的清理脚本。这类脚本风险最高。不要以为作者写对了就不会出事,路径拼错一个字符就可能是灾难。我的处理习惯是:拿到脚本后先做一次删除动作审计,再决定要不要上生产。

# 先列出脚本里所有删除动作(只读审计) grep -nE 'rm(-rf)?\s+|find\s+.*-delete' bin/*.sh

这一步不执行删除,只是把风险点列出来。看到rm -rf时,先确认它的目标路径是否由固定值或参数控制,再看有没有前置的目录存在性判断。比如rm -rf "$LOG_DIR/*"和rm -rf "$LOG_DIR"完全是两码事,前者删文件,后者连目录一起删。脚本里如果出现绝对路径写死的删除,并且没有参数保护,我一般会改成相对路径加变量,甚至直接停用。

5.5 现象:定时任务里脚本不输出,退出码为0但什么都没干

脚本手动跑正常,放进 crontab 之后要么不执行,要么执行了但日志找不到。最常见的两个原因:一个是 cron 环境里的 PATH 和你交互终端里的 PATH 不一样,脚本里用的命令找不到;另一个是脚本输出重定向到某个不存在的目录,cron 直接丢弃输出。

# 在脚本顶部固定 PATH 和关键变量 export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" export TZ="UTC"

把 PATH 写死在脚本顶部而不是依赖用户环境,是让脚本能在 cron 里稳定运行的底线操作。除了 PATH,还要检查脚本里有没有用相对路径,cron 的工作目录默认是用户家目录,相对路径很容易失效。日志文件尽量用绝对路径,并确保脚本运行时日志目录已经存在。

6. 把279个脚本变成自己的:养成“注释即文档、模板即复用”的小习惯

脚本库跑通只是第一步,真正让这279个脚本产生长期价值的方式,是把它拆成自己能复用的模板,而不是让一个庞大的合集一直占据磁盘。我现在的维护方式很简单:所有脚本只要经过改造,就把用法注释写成一两行,并保持统一的参数风格。

6.1 给每个脚本加 usage 函数,替代散落的 echo

我习惯在每个脚本开头加一个usage()函数,把接受的参数列出来,再在主逻辑里判断$#是否足够。这种做法的收益很直接:三个月后你回来看脚本,不用靠回忆;别人接手时,也不用打开正文读一遍。

#!/usr/bin/env bash set -Eeuo pipefail usage() { cat <<EOF 用法: $(basename "$0") <日志目录> [保留天数] 示例: $(basename "$0") /var/log/nginx 14 EOF exit 2 } [ $# -lt 1 ] && usage LOG_DIR="$1" KEEP_DAYS="${2:-7}"

6.2 从279个脚本里抽3个模板,而不是背诵所有脚本

把这个合集坚持用了三个月之后,我最大的心得是:不要试图记住每个脚本,而是总结出三个自己最常用的模板,例如“参数校验加退出码加输出规范”的巡检类模板、“环境变量加默认值加日志切割”的清理类模板、“while read加跳过注释加超时控制”的批量操作类模板。遇到新需求时,先在模板上改,而不是翻合集从头找。

6.3 验证脚本回归:改一行之后,跑一次它的反例

每次改动脚本之后,我习惯跑它最容易出错的反例,比如不传参数、传空目录、把阈值设成0。验证一遍不是为了说服自己它能跑,而是确认失败路径是可预期的。这个习惯救过我一次,日志切割脚本改完保留天数后,当天晚上定时任务跑完没误删,就是因为提前测了“目录不存在”和“文件为空”这两种情况。一套脚本敢用多久,不取决于它当时写了多好,而取决于你改它的时候有多稳。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询