首页 / 资讯中心 / 文章详情

Linux一键修复与安装脚本实战:从环境检测到自检回滚

Linux一键修复与安装脚本实战:从环境检测到自检回滚 ★ FEATURED ARTICLE
简介面向Linux系统管理员、运维工程师与初学者的自动化脚本合集专注解决多发行版系统修复与服务器环境快速搭建问题。包体共24个文件以17个Shell脚本为核心辅以YAML编排、Markdown说明、TXT适配记录及许可证文件整体仅44KB轻量易部署结构清晰便于按需裁剪。脚本按repair_scripts与install_scripts模块化组织前者涵盖系统检测、包管理器修复、引导重置、日志清理等修复策略后者支持Web、数据库、编程环境及科研工具等常见服务的一键安装与自动化配置并内置完善的安全校验与异常恢复机制可降低手动操作失误风险。同时配有Ubuntu、Debian等发行版专项说明与使用文档便于快速上手。已有153人学习下载适合需要高效完成系统维护、环境初始化或学习自动化运维脚本写法的读者参考。1. 一键修复与安装脚本到底解决什么问题从一次系统崩溃说起一台线上服务器因为磁盘写满导致 yum 源元数据损坏大量依赖包报错连sudo都开始闹脾气。你 SSH 进去想手动修但缺失的包一个接一个依赖关系像多米诺骨牌。这时候你最需要的不是一条一条敲命令而是一份能自动识别系统、检测损坏点、执行修复并回滚的「一键修复与安装脚本」。这套脚本的价值就是把 Linux 系统故障案例里最耗时的部分——环境识别、包管理器恢复、服务重装——压缩成一次可重复执行的自动化操作。本文所有方案都基于真实运维场景面向的是需要维护多台 Linux 服务器、又不想每次手动敲几十条命令的从业者。不管你是新手还是老手都能从这里拿走一套能直接改用的框架。2. 拆解一键脚本的骨架检测-备份-修复/安装-自检2.1 为什么不要用一条命令跑完的黑匣子写法我见过很多所谓一键脚本就是一段几百行的 shell 从头跑到尾中途不判断系统类型不记录执行状态失败也不给你任何提示。这种脚本在作者自己的环境里可能没问题换一台机器就翻车。一键脚本的核心不是少敲命令而是安全地把该做的事做完。所以第一步不是写修复逻辑而是定骨架。一个可靠的一键修复与安装脚本至少要分成四个阶段环境检测、备份、执行操作、自检回滚。环境检测决定下面所有命令怎么选备份决定你修坏了能不能回头执行操作要幂等也就是重复跑不会越修越坏自检则是确认这次操作真的生效了。这里我用一个执行流程的伪代码来说明实际 shell 脚本不会这么规整但逻辑必须分层。#!/bin/bash # 一键脚本骨架示例 set -euo pipefail # 出错即停变量未定义即报错管道错误不吞掉 detect_env() { # 此函数输出系统类型、包管理器、架构 echo [1/4] 检测环境 } backup_sys() { # 此函数备份将要改动的文件到 /root/backup_timestamp echo [2/4] 备份配置 } do_repair() { # 此函数根据 detect_env 的结果执行修复 echo [3/4] 执行修复 } self_check() { # 此函数验证关键服务或命令是否恢复 echo [4/4] 自检 } main() { detect_env backup_sys do_repair self_check } main $这段代码的逻辑说明set -euo pipefail是给脚本戴紧箍咒。-e表示任何一条命令返回非零就退出避免错误后继续执行导致连锁反应-u防止未定义变量被当成空串很多脚本翻车就是变量拼错却静默通过pipefail让管道中任何一段失败都算失败。四个函数各司其职main串起来。你可以看到骨架本身就带着检测-备份-修复/安装-自检的节奏后续所有的坑都在这四个环节里。2.2 最小可用的检测函数系统版本、包管理器、硬件架构最常见的问题就是脚本不知道自己在哪台机器上。你要修复 各种Linux系统 的仓库源不同的系统源格式、命令都不一样。我一般用/etc/os-release而不是uname因为uname只能告诉你内核版本不能告诉你这是 CentOS 还是 Ubuntu。用下面的函数可以拿到你需要的最小信息#!/bin/bash # detect_env.sh detect_env() { # 来源/etc/os-release 是系统自带的标准文件 if [ -f /etc/os-release ]; then . /etc/os-release OS_ID$ID # 例如 centos / ubuntu / debian / kylin OS_VERSION_ID$VERSION_ID # 例如 7 / 8 / 20.04 / 22.04 else echo 无法识别系统请手动检查 exit 1 fi # 根据 ID 选择包管理器 case $OS_ID in centos|rhel|anolis|opencloudos) PKG_MANAGERyum [ $OS_VERSION_ID \ 8 ] PKG_MANAGERdnf ;; ubuntu|debian|kylin|uos) PKG_MANAGERapt ;; alpine) PKG_MANAGERapk ;; *) echo 暂不支持的系统: $OS_ID exit 1 ;; esac # 架构检测 ARCH$(uname -m) echo 系统: $OS_ID $OS_VERSION_ID | 包管理器: $PKG_MANAGER | 架构: $ARCH }逻辑说明. /etc/os-release是把该文件里的变量直接导入当前 shell这是所有主流 Linux 发行版都遵循的标准。用$ID而不是$NAME是因为ID是稳定的机器可读字符串NAME是给人看的。包管理器选择上我加了版本判断因为 CentOS 8 之后yum已经变成dnf的软链接直接用yum也能跑但注意某些yum插件的路径不同。Architecture 用uname -m常见的是x86_64、aarch64这会影响你下载二进制包的地址。参数说明OS_VERSION_ID \ 8这个写法只在 bash 里有效用sort -V比较版本号更严谨如果你的系统是 CentOS 7yum是唯一选择。对于 Debian 系的kylin和uos它们底层是 apt但源配置路径有差异后面第 4 章会单独讲。2.3 备份与回滚给操作加后悔药一键修复脚本最可怕的是把原配置覆盖掉然后用户发现新配置启动不了。所以备份这一环不能省。我常用的是cp -r带时间戳备份到本地同时生成一个回滚脚本这样哪怕新配置搞砸了也能一键还原。#!/bin/bash # backup.sh BACKUP_BASE/var/backups/oneclick TS$(date %Y%m%d_%H%M%S) BACKUP_DIR${BACKUP_BASE}/${TS} backup_files() { # 参数为需要备份的文件或目录列表 mkdir -p $BACKUP_DIR for path in $; do if [ -e $path ]; then # 保留目录结构例如 /etc/nginx/nginx.conf - BACKUP_DIR/etc/nginx/nginx.conf dest${BACKUP_DIR}${path} mkdir -p $(dirname $dest) cp -a $path $dest else echo 警告: 路径不存在跳过备份: $path fi done # 生成回滚脚本 { echo #!/bin/bash echo # 回滚脚本恢复所有已备份文件 for path in $; do src${BACKUP_DIR}${path} if [ -e $src ]; then echo cp -a $src $path fi done } ${BACKUP_DIR}/rollback.sh chmod x ${BACKUP_DIR}/rollback.sh echo 备份完成: $BACKUP_DIR } # 示例用法修复 nginx 之前先备份它的配置和站点目录 backup_files /etc/nginx /usr/share/nginx/html逻辑说明cp -a保留属性、软链接和时间戳比cp -r更安全。回滚脚本是直接生成的命令序列不需要用户自己找备份路径。注意回滚脚本里的路径如果包含单引号会造成拼接问题我在实际项目中会再加一层转义这里为了可读性省略了。参数说明$接收所有传入路径dest${BACKUP_DIR}${path}直接把绝对路径拼在备份基底下能保留原结构。备份目录建议放在根分区而不是/tmp因为/tmp可能被系统定期清理。另外修复系统源之前我习惯把/etc/yum.repos.d/或/etc/apt/sources.list.d/整个目录备份因为改源是最容易出错也是影响面最大的一步。3. 写一个能扛住常见故障的一键修复脚本核心函数与参数设计3.1 修复 yum/apt 源与依赖损坏的两种场景服务器环境安装脚本里最常遇到的是源失效和依赖损坏。源失效表现为yum makecache一直超时依赖损坏表现为rpm -qa报一堆缺失依赖。修源的正确姿势不是直接删掉所有 .repo 文件而是先备份再替换为可用的镜像源。下面是个修复 CentOS 7 yum 源的例子#!/bin/bash # fix_yum_centos7.sh # 使用场景CentOS 7 源失效或默认源指向外网导致超时 fix_yum_source() { # 备份 local backup_dir/var/backups/yum_repos_$(date %Y%m%d_%H%M%S) mkdir -p $backup_dir cp -a /etc/yum.repos.d/* $backup_dir 2/dev/null || true # 删除现有所有 repo 文件避免混杂 rm -f /etc/yum.repos.d/*.repo # 写入国内镜像源示例为阿里云 cat /etc/yum.repos.d/CentOS-Base.repo EOF [base] nameCentOS-$releasever - Base baseurlhttp://mirrors.aliyun.com/centos/$releasever/os/$basearch/ gpgcheck0 enabled1 [updates] nameCentOS-$releasever - Updates baseurlhttp://mirrors.aliyun.com/centos/$releasever/updates/$basearch/ gpgcheck0 enabled1 [extras] nameCentOS-$releasever - Extras baseurlhttp://mirrors.aliyun.com/centos/$releasever/extras/$basearch/ gpgcheck0 enabled1 EOF # 清理缓存并重建 yum clean all yum makecache }逻辑说明gpgcheck0是关闭 GPG 校验方便脚本自动化。如果你需要安全级别高可以设置为 1 并导入相应 GPG 密钥但在一键修复场景下连通性比签名验证更紧迫。$releasever和$basearch是 yum 内部变量会在执行时自动替换为 7 和 x86_64不需要手动写死。删掉所有 repo 文件这步要谨慎因为很多公司有内网私有源我的建议是只匹配官方源的名称比如CentOS-开头的文件。再来看 apt 源修复常见于 Ubuntu 20.04 系统被改坏或者第三方源冲突#!/bin/bash # fix_apt_ubuntu.sh fix_apt_source() { # 备份 cp -a /etc/apt/sources.list /etc/apt/sources.list.bak.$(date %Y%m%d%H%M%S) if [ -d /etc/apt/sources.list.d ]; then cp -a /etc/apt/sources.list.d /etc/apt/sources.list.d.bak.$(date %Y%m%d%H%M%S) fi # 覆盖主源文件 cat /etc/apt/sources.list EOF deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse EOF # 清理第三方源中的无效条目这里是删除非 aliyun 和官方源避免干扰 for f in /etc/apt/sources.list.d/*.list; do if [ -f $f ] ! grep -q aliyun\|archive.ubuntu $f; then mv $f ${f}.disabled fi done apt-get update }逻辑说明这里把sources.list.d里的第三方源全部禁用掉因为一键修复场景下那些复杂的 PPA 往往是导致依赖冲突的根源。focal是 Ubuntu 20.04 的版本代号如果你要适配 22.04需要改成jammy。建议脚本里做成变量根据/etc/os-release自动映射版本代号而不是写死。参数说明apt 源不能用$releasever这种变量必须显式写版本代号。为了让脚本开源可维护我一般写一个codename_map函数把20.04映射成focal把22.04映射成jammy这样改起来方便。3.2 服务器环境安装的常见目标Nginx / PHP / MySQL 一键安装标题里的服务器环境安装脚本指的是什么最典型的是 LNMP 环境——Nginx、PHP、MySQL。这套组合在中小型业务里非常常见。一键安装不是简单yum install而是要处理编译参数、软链接、开机自启、目录权限这几个固定动作。下面给一个模块化的安装函数以 Nginx 为例#!/bin/bash # install_nginx.sh install_nginx() { local version${1:-nginx} # 允许传入版本默认系统源版本 if command -v nginx /dev/null 21; then echo nginx 已安装跳过。 return 0 fi # 安装前的依赖 if [ $PKG_MANAGER yum ] || [ $PKG_MANAGER dnf ]; then $PKG_MANAGER install -y nginx elif [ $PKG_MANAGER apt ]; then apt-get update apt-get install -y nginx fi # 确保服务开机自启 systemctl enable nginx systemctl start nginx # 验证是否真的起来了 systemctl status nginx --no-pager | head -n 5 }逻辑说明这个函数先检查command -v nginx已安装就直接退出。这是幂等性的基础——脚本重复跑不会重复装。systemctl enable是把服务做成开机自启start是立刻启动。注意我用| head -n 5限制输出防止状态信息刷屏。参数说明函数里的local version${1:-nginx}是给版本留接口实际生产环境我很少直接用系统源安装因为系统源里的 Nginx 版本偏旧。如果你需要新版 Nginx建议使用官方源但官方源要求你额外安装epel-release或在 apt 里添加 nginx 官方仓库这会增加不少判断分支。我的方案是先用系统源跑通最小闭环再把版本升级的优化第二步做。3.3 日志与状态机让脚本可以重复执行一键脚本翻车最常见的原因是执行到一半失败然后用户修了一下又重跑结果之前已完成的步骤被重复执行反而产生新问题。解决方式就是状态机——每一步执行前先检查一个标记文件确认这一步是否已经完成。#!/bin/bash # state_machine.sh STATE_FILE/var/run/oneclick_install.state set_state() { # $1 为步骤名称写入当前完成状态 echo $1 $STATE_FILE } check_state() { # $1 为步骤名称如果已完成返回0否则返回1 [ $(cat $STATE_FILE 2/dev/null) $1 ] } # 使用示例 if ! check_state source_repaired; then echo 修复源... fix_yum_source set_state source_repaired fi if ! check_state nginx_installed; then echo 安装 nginx... install_nginx set_state nginx_installed fi逻辑说明STATE_FILE只记录最后一个完成步骤。如果源修复后崩溃重跑时会从 nginx 开始而不是重新修源。这个设计比每次都全部重跑更接近人性。你也可以用更复杂的标记文件记录多个步骤但生产环境里一个简单字符串就够用了。参数说明标记文件放在/var/run/下重启后会被清空这意味着系统重启后重跑脚本会重新执行所有步骤符合预期。如果你想跨重启保持状态可以放到/var/lib/oneclick/下。另外cat $STATE_FILE时若文件不存在会输出空利用这个特性判断未开始。4. 各种Linux系统的适配清单CentOS / Ubuntu / Debian / 国产系统4.1 用 /etc/os-release 做统一入口无论是修复还是安装你的脚本必须能回答三个问题这个系统是什么分支Red Hat 系还是 Debian 系、包管理器是什么、init 系统是 systemd 还是 SysV。答案都在/etc/os-release里。常见系统的 ID 对照如下系统/etc/os-release 中的 ID包管理器源配置文件CentOS 7centosyum/etc/yum.repos.d/CentOS 8centosdnf/yum/etc/yum.repos.d/Rocky Linuxrockydnf/etc/yum.repos.d/AlmaLinuxalmalinuxdnf/etc/yum.repos.d/Ubuntuubuntuapt/etc/apt/sources.listDebiandebianapt/etc/apt/sources.listopenEuleropenEulerdnf/etc/yum.repos.d/麒麟kylinapt/etc/apt/sources.list.d/统信 UOSuosapt/etc/apt/sources.list.d/这个表格的价值在于你写 case 分支时可以直接引用$ID不需要额外判断厂商。比如case $OS_ID in centos|rocky|almalinux|openEuler)统一走 RPM 系逻辑ubuntu|debian|kylin|uos)统一走 dpkg 系逻辑。但注意 openEuler 的 ID 是大写带 Ebash 的 case 匹配大小写敏感我是先把变量转成小写再做匹配的。#!/bin/bash # normalize_os.sh normalize_os() { . /etc/os-release # 转小写统一匹配 echo $ID | tr [:upper:] [:lower:] }逻辑说明tr [:upper:] [:lower:]把大写转小写这在处理国产系统时特别重要。因为 openEuler 官方 os-release 里写的是IDopenEuler和其他系统风格不一致。你写脚本时不转小写case 匹配就会漏掉它。参数说明这里的转小写也适用于从VERSION_ID提取版本号。比如VERSION_ID22.04转小写没有意义但VERSION_IDV10这种麒麟版本号转小写后做字符串比较会更规范。4.2 包管理器差异与命令兼容层实际操作中yum 和 apt 的命令语法差异不仅是install参数还包含缓存清理、更新、自动确认这些细节。我的做法是写一个包管理器兼容层所有上层函数都调用统一接口。#!/bin/bash # pkg_should.sh pkg_install() { # $ 为包名列表 case $PKG_MANAGER in yum|dnf) $PKG_MANAGER install -y $ ;; apt) apt-get update -qq apt-get install -y $ ;; apk) apk add --no-cache $ ;; esac } pkg_remove() { case $PKG_MANAGER in yum|dnf) $PKG_MANAGER remove -y $ ;; apt) apt-get remove -y --purge $ ;; apk) apk del $ ;; esac } pkg_update() { case $PKG_MANAGER in yum|dnf) $PKG_MANAGER makecache ;; apt) apt-get update ;; apk) apk update ;; esac }逻辑说明pkg_install里的apt-get update -qq放在安装前是因为 apt 的索引可能过期而 yum 不需要每次都 clean。--purge表示卸载时连配置文件一起删这个要谨慎生产环境建议去掉--purge因为你不确定哪个配置以后还有用。参数说明${PKG_MANAGER}必须在全脚本内全局存在。如果是在函数里用变量可以通过环境变量传递或者用export PKG_MANAGER。我见过有人把包管理器变量写在函数内部结果调用pkg_install时为空直接执行install -y xxx看到这个命令没报错就知道踩了多大的坑。4.3 国产系统麒麟/统信的坑很多运维手里维护着国产 Linux 服务器尤其在企业内网。这些系统基于 CentOS 或 Debian 改造但有几个特殊点官方源往往需要授权或在内网环境访问部分命令被裁剪以及apt-get update时会报公钥缺失。#!/bin/bash # fix_kylin_apt.sh fix_kylin_source() { # 麒麟系统通用做法把源改为官方源或内网镜像 local codename$(grep VERSION_CODENAME /etc/os-release | cut -d -f2) # 常见 codename: kylin / yangtze / juhe if [ -z $codename ]; then codenamekylin fi # 备份 cp -a /etc/apt/sources.list.d/kylin.list /etc/apt/sources.list.d/kylin.list.bak.$$ 2/dev/null || true # 写入内网镜像源这里用示例 IP实际替换成你的内网源 cat /etc/apt/sources.list.d/kylin.list EOF deb http://192.168.1.10/ubuntu/ $codename main universe multiverse deb http://192.168.1.10/ubuntu/ $codename-security main universe multiverse deb http://192.168.1.10/ubuntu/ $codename-updates main universe multiverse EOF # 导入公钥如果内网源使用自签证书或本地仓库 apt-get update 21 | grep -q NO_PUBKEY { key_id$(apt-get update 21 | grep NO_PUBKEY | awk {print $NF}) echo 缺少公钥: $key_id # 常见做法从内网服务器下载公钥并导入 wget -q -O- http://192.168.1.10/repo/public.key | apt-key add - } }逻辑说明国产系统的坑在于源配置路径不统一有的在/etc/apt/sources.list.d/下有的直接改主文件。所以我先备份然后强制写入一个干净的.list文件。公钥错误是高频故障grep -q NO_PUBKEY检测后再导入可以避免 apt 源安装时报错。参数说明$$是当前进程号用它做备份文件名后缀可以避免并发冲突。codename如果不识别默认kylin但不同版本的麒麟 codename 差异很大建议你在脚本里打日志把codename打印到文件中方便事后排查。5. 一键脚本的避坑指南5个真实翻车现场5.1 现象脚本执行到一半断网再跑直接报错有一次我在内网重装一台跳板机的 Nginx脚本执行到yum install时网络闪断进程被杀。我重新运行脚本它从头开始又去改源。结果改源时发现 repo 文件已被备份目录占满导致后续所有操作都挫败。原因脚本没有状态记录且备份目录每次运行都会新建没有清理机制导致磁盘被历史备份占满。解决第一引入状态机见 3.3 节已完成的步骤直接跳过。第二备份目录只保留最近 3 次用find找出旧目录并删除。第三在脚本开始前检查磁盘空间低于 500MB 直接退出。# 保留最近3份备份 ls -dt /var/backups/oneclick/* | tail -n 4 | xargs rm -rf逻辑说明ls -dt按时间倒序列出所有备份tail -n 4跳过前 3 个最新的剩下的全部删除。这条命令放在备份之后、执行操作之前避免备份无限堆积。5.2 现象把CentOS当Ubuntu修导致源替换失败同事写了一个一键修复脚本里面判断系统用uname -a看到内核里有el7字样就调 CentOS 逻辑。结果这台机器是 Oracle Linux同样有 el7 标识但它的源配置在/etc/yum.repos.d/public-yum-ol7.repo脚本强行删了所有 repo导致系统无法安装任何包。原因检测依据错误没有使用/etc/os-release。解决统一使用os-release的 ID 字段。同时在脚本里加入白名单判断只允许已知系统 ID 继续执行其他系统直接报不支持并退出。# 安全检测 case $OS_ID in centos|rhel|rocky|almalinux|openEuler|ubuntu|debian|kylin|uos) ;; *) echo 未识别的系统: $OS_ID脚本终止以防误操作 exit 1 ;; esac逻辑说明这个白名单是最后的保险。就算前面检测逻辑写错了白名单也能拦截住不认识的系统。生产环境里宁可脚本拒绝执行也不能让它在一台你没见过的系统上乱跑。5.3 现象重装Nginx后原有站点配置全丢了有个项目组用一键脚本重新安装 Nginx 以修复module缺失问题脚本执行了rm -rf /etc/nginx再安装新包。结果所有站点的server_name和反向代理配置都丢了回滚备份又用的是cp -r软链接关系混乱。原因修复动作做成重装而不是增量修复。重装前没有备份配置且备份时没有保留软链接。解决修复 Nginx 时绝不停掉整个服务再删目录。应该用yum reinstall nginx或apt-get install --reinstall nginx这个命令只覆盖二进制文件不碰配置目录。如果真的需要复位配置也要先把/etc/nginx整体备份并且回滚用cp -a保留软链。# 推荐的重装方式 pkg_remove nginx nginx-common pkg_install nginx # 注意不要手动 rm -rf /etc/nginx除非你明确知道自己在做什么逻辑说明pkg_remove用apt-get remove --purge会删除配置所以如果必须用 remove/reinstall去掉--purge参数。但更好的方案是只用pkg_install里的reinstall逻辑我一般会给包管理器扩展一个pkg_reinstall函数。5.4 现象脚本在容器里检测到systemd但没用我在 Docker 容器里测试一键脚本想修复某个服务。脚本检测到systemctl存在然后执行systemctl restart nginx。结果容器内实际上没有 PID 1 是 systemd命令报错。但脚本没有捕获错误继续往下走导致最终状态看似成功实际服务没起来。原因没有区分systemd 可用和systemctl 命令存在。容器内通常没有 systemd 作为 init。解决在执行服务管理命令前检查/run/systemd/system目录是否存在这是 systemd 是否运行的可靠标记。# 判断 systemd 是否真正在运行 if [ -d /run/systemd/system ]; then systemctl start $1 else # 容器或无 systemd 的系统中改用 service 命令 service $1 start fi逻辑说明/run/systemd/system只在 systemd 作为 PID 1 时存在。如果没有这个目录你就要用service命令或直接执行启动脚本。另一种方案是判断容器环境变量但不可靠。这个坑在修复型脚本里特别多因为修复脚本大多数拷贝到故障机器上跑而故障机器的 systemd 可能已经挂掉。5.5 现象版本检测用uname而不是/etc/os-release导致误判更新脚本时为了适配新系统我把检测内核版本的地方改成了uname -r结果拿到的是3.10.0我误判为 CentOS 7实际它是 CentOS 8 的内核反而显示4.18。非但没修好还可能因为判断错误执行了错误的源。原因uname -r返回的是内核版本和发行版版本没有直接对应关系。CentOS 7 全系列是 3.10CentOS 8 是 4.18但你不能反推。解决永远用 os-release 的VERSION_ID字段。如果拿不到用rpm -q --qf %{VERSION} centos-release或者dpkg -l查询发行版包。下面是备用检测示例if [ -z $OS_VERSION_ID ]; then case $OS_ID in centos|rhel) OS_VERSION_ID$(rpm -q --qf %{VERSION} centos-release 2/dev/null | cut -d. -f1) ;; ubuntu) OS_VERSION_ID$(dpkg -l base-files | awk /^ii/{print $3} | cut -d. -f1) ;; esac fi逻辑说明rpm -q查询的 centos-release 包的版本就是系统版本比 uname 可靠。ubuntu 下查 base-files 的版本号也能拿到 20/22 这种主版本。这实际上是给 /etc/os-release 缺失的环境做兜底但绝大多数主流系统都有 os-release 文件。6. 最后的进阶技巧把一键脚本做成交互式菜单与验证闭环6.1 一个带彩色输出和交互选择的框架直接给脚本加交互菜单能避免用户误操作。我用一个简单的select循环每个选项对应一个功能。彩色输出用tput而不是硬编码 ANSI 转义这样在不同终端下不会乱码。#!/bin/bash # oneclick_menu.sh GREEN$(tput setaf 2) RED$(tput setaf 1) NC$(tput sgr0) show_menu() { echo ${GREEN}请选择要执行的操作:${NC} echo 1) 修复系统软件源 echo 2) 安装 Nginx echo 3) 安装 PHP echo 4) 安装 MySQL echo 5) 全流程执行修复源 安装环境 echo 0) 退出 } run_action() { case $1 in 1) fix_yum_source ;; 2) install_nginx ;; 3) install_php ;; 4) install_mysql ;; 5) fix_yum_source install_nginx install_php install_mysql ;; 0) exit 0 ;; *) echo ${RED}无效选项${NC};; esac } while true; do show_menu read -p 输入数字: choice run_action $choice echo done逻辑说明这个菜单不依赖 whiptail 或 dialog纯 bash 实现适合最小化系统。GREEN和RED用tput生成结尾NC恢复默认颜色。read -p读取用户输入case分发到对应函数。全流程选项里用了前面失败就不会继续执行后面的安装这个比较符合修复场景的预期。6.2 验证闭环修复完如何确认真的好了一键脚本的最后一步必须是自检。不是打印完成两个字就结束而是真的去检查服务端口、配置文件语法、命令版本。# 验证 nginx 是否可用 if nginx -t /dev/null 21; then echo nginx 配置语法正确 else echo nginx 配置语法错误执行回滚 bash $BACKUP_DIR/rollback.sh exit 1 fi # 验证 80 端口是否监听 if ss -tlnp | grep -q :80 ; then echo nginx 正在监听 80 端口 else echo nginx 未监听 80 端口请检查启动日志 fi逻辑说明nginx -t是 Nginx 自带的配置测试只检查语法不重启。如果配置错误立即执行 rollback.sh 恢复备份并把退出码设为非 0让调用方知道这次修复没有成功。ss -tlnp检查端口监听比curl localhost更少依赖额外模块。这两个节选就是我日常写脚本的收尾习惯。也因为我犯过修复完直接重启服务结果配置错误导致业务中断半小时的错误所以现在所有一键脚本必须带自检和回滚两个动作。做这个方向最大的教训是越是想省事越要在检测和备份上多花功夫。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站