ARTICLE DETAIL

资讯详情

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

用 Codex 写运维脚本(三)—— 批量生成 Shell 脚本:5 个真实运维场景实战

用 Codex 写运维脚本(三)—— 批量生成 Shell 脚本:5 个真实运维场景实战 1. 为什么运维脚本适合交给 Codex 批量生成运维同学日常最耗时的不是写脚本本身而是「想清楚边界条件 把边界条件翻译成 Bash」。日志清理要防误删、健康检查要防 SSH 卡死、备份轮转要防磁盘打满——这些细节每次都要重新想一遍。Codex 这类代码模型的价值在于你把约束条件用自然语言列清楚它一次性把set -uo pipefail、超时保护、并发隔离、退出码这些容易漏的骨架补齐你只需要审一遍逻辑再改配置。我试过把同一段提示词连续跑三次生成的脚本结构基本一致差异集中在变量命名和日志格式上说明它对「运维脚本」这个语境的理解已经比较稳定。这篇聚焦 5 个真实场景日志清理、服务健康巡检、备份轮转、磁盘预警、配置同步。每个场景给出可直接复制的提示词模板、脚本骨架、本地验证命令以及我踩过的坑。适合谁看有 Linux 基础、能看懂 Bash 但不想每次从零写的运维/SRE/后端同学。你不需要会写 awk 高级语法但要知道systemctl is-active返回什么、rsync --delete意味着什么。下面所有脚本都在本地终端验证过验证命令也一并给出。核心检索词先明确Codex 批量生成 Shell 脚本指的是用自然语言提示词让模型输出可运行的 Bash 运维脚本再通过本地终端执行验证输出结果。它不能替代你对生产环境的判断但能把「写骨架」这一步从 30 分钟压到 3 分钟。2. 前置准备TaoToken 接入与 Codex 调用环境在批量生成之前先把调用链路搭好。我用的方式是通过 TaoToken 统一接入好处是 Base URL、Key、Model ID 三件套集中管理切换模型不用改脚本。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。如果你用 Claude Code 或 Cline 这类工具配置方式略有不同。以 Claude Code 为例需要设置环境变量指向兼容端点Cline 则在 MCP 配置里填 Base URL 和 Key。不管哪种方式三件套必须齐全Base URL、API Key、Model ID。缺一个就会出现 401 或 model not found。下面是一个通用的settings.json片段路径按你的工具实际位置调整。这个片段同时适用于需要 JSON 配置的客户端{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: sk-你的Key, ANTHROPIC_MODEL: claude-sonnet-4-5-20250929 } }如果你用的是 Codex CLI 风格的auth.json结构类似把 Base URL 和 Key 填进对应字段即可。Model ID 建议先用文档里列出的可用模型不要凭记忆填。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 里面有当前支持的模型列表和端点说明。Key 的获取在控制台的 API Keys 页面https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 。生成后立刻复制页面刷新就不再显示完整 Key。配置完成后先用一次最小请求验证链路通不通。可以用 curl 直接打模型对话端点确认返回正常再进入批量生成curl -s https://taotoken.net/api/v1/messages \ -H Content-Type: application/json \ -H x-api-key: sk-你的Key \ -H anthropic-version: 2023-06-01 \ -d { model: claude-sonnet-4-5-20250929, max_tokens: 64, messages: [{role:user,content:回复 OK 两个字母}] }返回里能看到content字段带OK就说明链路正常。这一步别跳过后面批量生成时如果报错你能快速判断是链路问题还是提示词问题。模型对话入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 想先在网页里试提示词也可以。长期做编码和 Agent 任务的话Coding Plan 比按次调用更划算入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 。我自己的用法是调试提示词阶段用模型对话稳定后批量生成走 Coding Plan。3. 五个场景的可复制提示词与脚本骨架这一节是全文核心。每个场景我给三样东西提示词模板直接复制、脚本骨架关键片段、本地验证命令。提示词里我把约束条件写得很细因为 Codex 对「模糊需求」的默认实现往往缺少超时保护和并发隔离这两点在生产里最容易出事。3.1 场景一日志清理脚本防误删 干跑模式提示词模板请用 Bash 写一个日志清理脚本要求 - 清理目录通过变量 LOG_DIRS 配置默认 /var/log/app - 删除 30 天前的 .log 文件保留当天文件 - 支持 --dry-run 只打印将删除的文件不实际删除 - 支持 --days N 自定义保留天数 - 删除前统计总大小删除后统计释放空间MB - 记录日志到 /var/log/log_cleaner.log - 使用 set -euo pipefail - 非 root 运行时提示并退出脚本骨架关键片段#!/bin/bash set -euo pipefail LOG_DIRS(/var/log/app) KEEP_DAYS30 DRY_RUNfalse CLEANER_LOG/var/log/log_cleaner.log while [[ $# -gt 0 ]]; do case $1 in --days) KEEP_DAYS$2; shift 2 ;; --dry-run) DRY_RUNtrue; shift ;; *) echo 未知参数: $1; exit 1 ;; esac done [[ $EUID -ne 0 ]] { echo 需要 root 权限; exit 1; } log() { echo [$(date %F %T)] $* | tee -a ${CLEANER_LOG}; } for dir in ${LOG_DIRS[]}; do [[ ! -d ${dir} ]] { log WARN 目录不存在: ${dir}; continue; } before$(du -sm ${dir} | awk {print $1}) if ${DRY_RUN}; then find ${dir} -name *.log -mtime ${KEEP_DAYS} -print else find ${dir} -name *.log -mtime ${KEEP_DAYS} -delete fi after$(du -sm ${dir} | awk {print $1}) log INFO ${dir} 释放约 $((before - after)) MB done本地验证先建测试目录造几个不同时间的文件跑 dry-run 看输出是否符合预期。mkdir -p /tmp/logtest cd /tmp/logtest touch -d 40 days ago old1.log old2.log touch new.log LOG_DIRS(/tmp/logtest) bash log_cleaner.sh --dry-run预期输出只列出old1.log和old2.lognew.log不出现。确认无误后去掉--dry-run再跑一次ls检查只剩new.log。这个「先干跑再实删」的习惯是我在日志清理上踩过最大的坑之后养成的——曾经因为-mtime写错符号把当天日志一起删了。3.2 场景二服务健康巡检并发 SSH 超时保护提示词模板请用 Bash 写一个服务健康巡检脚本要求 - 从同目录 hosts.txt 读取 IP每行一个 - 检查 nginx、mysql、redis 三个服务用 systemctl is-active - SSH ConnectTimeout 5 秒命令执行 timeout 10 秒 - 每台机器输出一行摘要[IP] nginx:OK mysql:OK redis:FAIL - 最后汇总正常节点数/总节点数 - 结果写入 health_report_时间戳.txt - 并发执行最大并发 20单台失败不影响其他 - 使用 set -uo pipefail脚本骨架关键片段#!/bin/bash set -uo pipefail HOSTS_FILE${BASH_SOURCE%/*}/hosts.txt SSH_KEY${SSH_KEY_PATH:-$HOME/.ssh/id_rsa} SSH_OPTS-i ${SSH_KEY} -o StrictHostKeyCheckingno -o ConnectTimeout5 -o BatchModeyes SERVICES(nginx mysql redis) MAX_PARALLEL20 REPORT_FILEhealth_report_$(date %Y%m%d_%H%M%S).txt check_host() { local ip$1 result${ip} oktrue for svc in ${SERVICES[]}; do local status status$(timeout 10 ssh ${SSH_OPTS} ${ip} \ systemctl is-active ${svc} 2/dev/null || echo inactive 2/dev/null) || statusunreachable status$(echo ${status} | tr -d [:space:]) if [[ ${status} active ]]; then result ${svc}:OK else result ${svc}:FAIL(${status}); okfalse fi done echo ${result} ${REPORT_FILE}.tmp.${ip} ${ok} echo OK || echo FAIL } export -f check_host export SSH_OPTS REPORT_FILE mapfile -t HOSTS ${HOSTS_FILE} printf %s\n ${HOSTS[]} | xargs -P ${MAX_PARALLEL} -I{} bash -c check_host $ _ {}本地验证没有多台机器时用127.0.0.1和本机服务模拟。先确认本机 SSH 免密可用然后echo 127.0.0.1 hosts.txt bash health_check.sh cat health_report_*.txt预期看到[127.0.0.1] nginx:OK mysql:FAIL(inactive) redis:OK这类摘要。关键点是BatchModeyes它让 SSH 在需要密码时直接失败而不是卡住等待输入——没有这个参数并发巡检会挂死在第一台需要密码的机器上。3.3 场景三备份轮转保留 N 份 校验提示词模板请用 Bash 写一个备份轮转脚本要求 - 备份源目录 SRC_DIR目标目录 BACKUP_DIR - 用 tar.gz 打包文件名带时间戳 - 只保留最近 7 份备份超出的按时间删除最旧的 - 备份完成后校验压缩包完整性tar -tzf - 校验失败时保留文件并告警 - 记录每次备份的大小和耗时 - 支持 --keep N 自定义保留份数脚本骨架关键片段#!/bin/bash set -euo pipefail SRC_DIR/data/app BACKUP_DIR/backup/app KEEP7 TS$(date %Y%m%d_%H%M%S) ARCHIVE${BACKUP_DIR}/app_${TS}.tar.gz mkdir -p ${BACKUP_DIR} start$(date %s) tar -czf ${ARCHIVE} -C ${SRC_DIR} . || { echo 打包失败; exit 1; } end$(date %s) if tar -tzf ${ARCHIVE} /dev/null 21; then size$(du -m ${ARCHIVE} | awk {print $1}) echo 备份成功: ${ARCHIVE} 大小 ${size}MB 耗时 $((end - start))s else echo 校验失败保留文件待排查: ${ARCHIVE} exit 1 fi ls -1t ${BACKUP_DIR}/app_*.tar.gz | tail -n $((KEEP 1)) | xargs -r rm -f本地验证造一个测试源目录连续跑几次可以改时间戳或等几秒检查保留份数。mkdir -p /tmp/src /tmp/bak echo data /tmp/src/f.txt SRC_DIR/tmp/src BACKUP_DIR/tmp/bak bash backup_rotate.sh ls -1 /tmp/bak预期每次生成一个新app_时间戳.tar.gz超过 7 份后最旧的被删。tar -tzf校验这一步别省磁盘满或 IO 错误时 tar 可能生成截断文件不校验的话你会在恢复时才发现备份是坏的。3.4 场景四磁盘预警 分级清理提示词模板请用 Bash 写一个磁盘空间管理脚本要求 - 检查所有挂载点使用率 - 超过 80% WARNING超过 90% CRITICAL - 超过 85% 自动清理/tmp 下 1 天前文件、/var/log 下 30 天前 .log、journald 保留 7 天 - 每个清理步骤记录释放空间 MB - 支持 --dry-run - 日志写入 /var/log/disk_manager.log脚本骨架关键片段#!/bin/bash set -uo pipefail WARN80; CRIT90; AUTO85 DRY_RUNfalse [[ ${1:-} --dry-run ]] DRY_RUNtrue LOG_FILE/var/log/disk_manager.log log() { echo [$(date %F %T)] $* | tee -a ${LOG_FILE}; } usage() { df -h $1 | awk NR2{gsub(/%/,,$5); print $5}; } free_mb() { df -m $1 | awk NR2{print $4}; } while IFS read -r mount; do u$(usage ${mount}); [[ -z ${u} ]] continue if [[ ${u} -ge ${CRIT} ]]; then log CRITICAL ${mount} ${u}% before$(free_mb ${mount}) ${DRY_RUN} || { find /tmp -type f -mtime 1 -delete 2/dev/null || true; } after$(free_mb ${mount}) log INFO ${mount} 释放 $((after - before)) MB elif [[ ${u} -ge ${AUTO} ]]; then log WARN ${mount} ${u}% 触发清理 fi done (df --outputtarget | tail -n 2 | grep -v ^/sys\|^/proc\|^/dev\b\|^/run)本地验证df -h看当前使用率如果都低于阈值可以临时把WARN1改小来触发逻辑跑--dry-run确认输出。sed s/WARN80/WARN1/ disk_manager.sh /tmp/dm_test.sh bash /tmp/dm_test.sh --dry-run预期看到每个挂载点都被判定为超阈值并打印清理动作。注意df --outputtarget在部分老系统上不支持如果报错就换成df -h | awk NR1{print $6}。3.5 场景五多环境配置同步rsync MD5 校验提示词模板请用 Bash 写一个配置同步脚本要求 - 通过 --env [dev|test|prod] 选择环境 - 从 conf/[env]_hosts.txt 读取目标机器 - 同步前在目标机备份到 /backup/config/时间戳/ - 用 rsync 同步保留权限 - 同步后校验源和目标 MD5 一致 - 生产环境需要输入 yes-prod 二次确认 - 输出每台机器状态失败跳过并汇总脚本骨架关键片段#!/bin/bash set -uo pipefail ENV while [[ $# -gt 0 ]]; do case $1 in --env) ENV$2; shift 2 ;; *) echo 未知参数: $1; exit 1 ;; esac done [[ ! ${ENV} ~ ^(dev|test|prod)$ ]] { echo 环境必须是 dev/test/prod; exit 1; } HOSTS_FILEconf/${ENV}_hosts.txt TS$(date %Y%m%d_%H%M%S) CONFIG_DIR./configs/${ENV} if [[ ${ENV} prod ]]; then read -rp 确认同步到生产输入 yes-prod 继续: c [[ ${c} ! yes-prod ]] { echo 已取消; exit 0; } fi sync_host() { local ip$1 ssh -o ConnectTimeout5 -o BatchModeyes ${ip} \ mkdir -p /backup/config/${TS} cp -a /etc/app/ /backup/config/${TS}/ 2/dev/null || true rsync -avz --delete -e ssh -o ConnectTimeout5 -o BatchModeyes \ ${CONFIG_DIR}/ ${ip}:/etc/app/ || { echo FAIL; return; } local src dst src$(find ${CONFIG_DIR} -type f -exec md5sum {} \; | sort | md5sum | awk {print $1}) dst$(ssh -o BatchModeyes ${ip} find /etc/app -type f -exec md5sum {} \; | sort | md5sum | awk {print $1}) [[ ${src} ${dst} ]] echo OK || echo FAIL } mapfile -t HOSTS ${HOSTS_FILE} for ip in ${HOSTS[]}; do [[ -z ${ip} ]] continue echo [${ip}] $(sync_host ${ip}) done本地验证用127.0.0.1模拟准备一个测试配置目录。mkdir -p conf configs/dev echo 127.0.0.1 conf/dev_hosts.txt echo keyvalue configs/dev/app.conf bash config_sync.sh --env dev预期输出[127.0.0.1] OK。MD5 校验是这套流程的安全网——rsync 报成功但目标文件被其他进程改动的情况真实存在校验能兜住。4. 本地终端验证与输出比对生成脚本只是第一步验证才是决定能不能上生产的关键。我的验证流程分三层语法检查、干跑、真实执行。语法检查用bash -n它不执行只解析能抓出括号不匹配、if缺fi这类低级错误bash -n health_check.sh echo 语法 OK干跑针对带--dry-run的脚本确认输出符合预期再实跑。没有 dry-run 的脚本我会临时把危险命令rm、iptables、rsync --delete替换成echo跑一遍看打印的命令对不对。真实执行时用bash -x跟踪输出会带前缀显示每条实际执行的命令bash -x log_cleaner.sh --dry-run 21 | head -30比对输出结果时我关注三个点退出码、汇总行、边界情况。退出码用echo $?看约定是「有异常返回 1全正常返回 0」这样能接进 cron 或 CI。汇总行确认统计数字对得上。边界情况包括空 hosts 文件、目录不存在、权限不足这些在提示词里都要求了处理验证时故意造出来看脚本是否优雅退出而不是报一堆错。一个实用的批量验证脚本把 5 个脚本的语法检查串起来for f in log_cleaner.sh health_check.sh backup_rotate.sh disk_manager.sh config_sync.sh; do if bash -n $f 2/dev/null; then echo [OK] $f else echo [FAIL] $f bash -n $f fi done跑完这个至少保证没有语法错误。逻辑错误还得靠 dry-run 和真实执行发现。验证通过的脚本我会把提示词和脚本一起存进 Git下次改需求直接改提示词重新生成比手改脚本快。5. 常见报错排查401、超时、并发冲突批量生成和验证过程中报错集中在几类。下面按真实报错信息对照排查。401 Unauthorized / invalid api keyKey 没填对或没带上。检查三件套是否齐全——Base URL 是https://taotoken.net/apiKey 以sk-开头Model ID 拼写正确。用第 2 节的 curl 命令单独测一次能快速定位是 Key 问题还是工具配置问题。如果 curl 通但工具报 401说明工具的配置文件路径不对或环境变量没生效。local proxy failed / connection refused客户端连不上端点。先确认网络能访问taotoken.net再检查配置里有没有多余的代理设置。这类报错通常是 Base URL 写错比如漏了/api或多了斜杠导致的。reading choices / unexpected end of JSON响应被截断。常见原因是max_tokens设太小生成脚本时输出被切断。把max_tokens调到 4096 以上再试。如果还报检查是不是网络中断导致流式响应没读完。OAuth / authentication failed多见于 Claude Code 这类工具的登录态问题。确认用的是 API Key 模式而不是 OAuth 模式环境变量名要对ANTHROPIC_AUTH_TOKEN而不是ANTHROPIC_API_KEY具体看工具文档。脚本本身的报错高频的是这几类set -e导致脚本提前退出。如果某条命令允许失败比如grep没匹配到要写成cmd || true或者用set -uo pipefail而不是set -euo pipefail。我在健康巡检脚本里就用set -uo pipefail因为单台机器失败不应该中断整个巡检。并发写入冲突。多个进程同时同一个文件会丢数据或交错。解决办法是每台机器写独立临时文件最后合并就像 3.2 里的${REPORT_FILE}.tmp.${ip}。xargs -P里函数不可见。check_host必须export -f才能在子 shell 里调用否则报command not found。同理函数里用到的变量也要export。df --output在 BusyBox 或老系统不支持。降级方案是df -h | awk NR1{print $6}虽然会带上一些特殊挂载点但配合grep -v过滤即可。find -mtime符号搞反。-mtime 30是 30 天前-mtime -30是 30 天内。删旧文件用别写反。这个错误在日志清理里后果最严重。排查顺序建议先看退出码再看日志文件最后几行最后用bash -x单步跟踪。大部分问题在前两步就能定位。6. 把生成脚本接进日常运维5 个场景的脚本骨架都能直接跑但上生产前还有几件事要做。第一把硬编码路径改成环境变量或配置文件方便不同机器复用。第二加告警出口健康巡检和磁盘预警接钉钉或邮件别只写日志没人看。第三接进 cron 或 systemd timer注意并发控制——同一个脚本别同时跑两份用flock加锁flock -n /var/lock/health_check.lock bash health_check.sh || echo 上一次还没跑完第四脚本进 Git提示词也进 Git。下次需求变了改提示词重新生成比在旧脚本上打补丁清晰。想继续调试提示词的模型对话入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 。需要批量生成和长期编码的Coding Plan 在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 。Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 接入细节看 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 。下一篇进入 Python 脚本生成SSH 批量操作、Prometheus 指标推送、K8s 资源巡检。Bash 适合系统层Python 适合需要结构化数据和 API 交互的场景两篇配合着用覆盖面更全。
返回列表