简介:本资源是面向Proxmox VE 7.x至9.x系统管理员与虚拟化爱好者的Shell一键运维工具包,聚焦换源加速、关闭订阅提示干扰及GPU/PCIe硬件直通三大高频痛点场景,显著降低开源虚拟化平台的日常维护门槛。压缩包共84个文件,含72张实操截图(JPG)用于关键步骤可视化指引,6个GPG签名文件保障源可信性,3张说明图(PNG)与1个核心脚本pve.sh构成自动化执行主体,另附README.md文档和GVT-G直通辅助工具,整体体积仅10.38MB,轻量易部署。目前已有238人下载学习,适用于从新手到进阶用户快速完成系统初始化优化——无需逐行编辑配置,一键执行即可实现国内镜像源切换、Web界面订阅弹窗永久屏蔽,并完成IOMMU启用、VFIO绑定及显卡直通等复杂操作的标准化落地。 玩 Proxmox VE 的朋友应该都有同感:系统装完之后,最先要处理的永远是三件事——换源、关订阅提示、配硬件直通。原因很直接,官方源在国内更新速度不稳定,未订阅的 enterprise 源一执行apt update就报 401,每次登录 Web 界面还要弹一个订阅提醒,想直通显卡或网卡又得手动改 GRUB、加载 VFIO 模块,命令又多又碎。与其每次都去翻教程,我把这三件事做成了一个 Shell 一键脚本,专治 PVE 7.x 到 9.x 的新装环境。这篇文章会把脚本的设计思路、每一行核心命令的原理、以及我实际跑过的坑都讲清楚,适合刚装好 PVE 想少走弯路的人参考。
1. 为什么把换源、关订阅、直通放进同一个脚本
1.1 PVE 装完后的“新机三件套”
Proxmox VE 本质上是一个基于 Debian 的带 Web 管理界面的虚拟化平台,装完之后默认的软件源是官方源和订阅源。官方源本身没问题,但如果你在国内,apt update和下包的速度经常让人怀疑网络是不是坏了。而订阅源enterprise.proxmox.com需要有效的订阅 key,没订阅的情况下执行更新会直接报 401 错误,不会影响现有服务,但会干扰后续安装依赖。
更烦的是 Web 界面右上角的订阅提示,每次登录都弹一遍“No valid subscription”。这个提示是前端 JavaScript 里检测到订阅状态后弹出来的,数据上不影响功能,但视觉上非常打断操作。网上虽然有很多“抄一段命令”的教程,但版本一变、文件路径一变,命令就失效了。
硬件直通就更不用说了,你想把一块显卡、一张网卡或者 HBA 卡直接分配给虚拟机,需要开启 CPU 的 VT-d/AMD-Vi,修改内核对 IOMMU 的支持,还要把设备从系统自带驱动中摘出来,绑定到 vfio-pci。整个过程牵扯到 GRUB、initramfs、modprobe 配置,任何一个环节漏掉,重启后要么 IOMMU 没生效,要么虚拟机直接起不来。
这三件事听起来独立,实际都集中在系统底层配置层面,而且都要改系统文件、都需要重启部分服务才能生效。把它们做进同一个交互式脚本里,既能减少重复输入,也能在脚本层面统一处理备份、回滚和版本兼容问题。这其实就是我写这个方案的初衷:把新装 PVE 后最机械、最容错的几个操作,封装成一条可重复执行、可维护的流程。
1.2 脚本设计原则:备份第一、幂等执行、交互选择
写这类系统配置脚本,我给自己定了几条硬性原则。
第一,备份必须无条件优先。任何对/etc/apt/、/etc/default/grub、/usr/share/javascript/下文件的修改,都要在动手前复制一份带日期的.bak文件。这不是形式主义,是给自己留退路。有一次我在 PVE 8.1 上做换源,直接覆盖了pve-no-subscription.list,后来发现写漏了一行注释,结果apt update疯狂报错,最后靠备份文件几分钟就恢复了。脚本里所有sed -i和重定向写文件的地方,前面都必须有cp操作。
第二,脚本要幂等。也就是同一个脚本跑两遍、三遍,结果应该是一样的,不会因为重复执行而生成一堆重复的源条目,或者把已经改过的 JS 文件再改一遍导致语法错误。实现幂等的方式很笨但有效:写文件前先判断是否存在,用sed替换时先确认匹配模式,能覆盖的就不追加,能注释的就不删除。
第三,交互式选择。不是所有人第一次跑脚本都需要做硬件直通,可能只想了换源和关闭提示。脚本应该提供菜单,让用户自己选要执行哪部分,而不是一股脑全部执行。后面我会给出一个基于 Bashselect的菜单实现,实际用下来非常顺手。
最后还要有一条红线:脚本只做标题里说的三件事,不碰系统和虚拟机的其他配置。很多“一键脚本”喜欢顺手优化内核参数、装一堆工具包,看起来很贴心,实际上出了问题很难排查。我倾向于把脚本做得“窄”一点,每一条命令都能说清楚为什么存在。
2. 换源模块:从源结构到可用脚本
2.1 先搞清楚 PVE 的 apt 源在管哪些事
换源这件事听起来简单,但 PVE 的 apt 源并不是一个文件能概括的。Debian 底层的/etc/apt/sources.list管系统基础包,PVE 自己的源分散在/etc/apt/sources.list.d/目录下。常见的有三个:
pve-enterprise.list:订阅用户使用的企业源,地址是enterprise.proxmox.com/debian/pve。没订阅时访问会 401。pve-no-subscription.list:社区免费源,地址是download.proxmox.com/debian/pve,也是pve-no-subscription仓库。这个源不需要订阅,更新速度也还可以,但在国内访问依然不算快。ceph.list:如果你启用了 Ceph,这里会列出 Ceph 相关的企业源。普通用户通常用不到,但脚本里应做兼容。
不同 PVE 版本对应不同的 Debian 代号,换源时这一步最容易翻车。PVE 7.x 对应 Debian 11 bullseye,PVE 8.x 对应 Debian 12 bookworm,PVE 9.x 对应 Debian 13 trixie。镜像站里的 Proxmox 源路径通常是这样的格式:
https://mirrors.tuna.tsinghua.edu.cn/proxmox/debian/bullseye所以脚本第一件事就是检测当前 PVE 主版本号,再映射到代号,然后决定往源文件里写哪个版本路径。
国内镜像站我常用清华、中科大、阿里云,这三家对 Proxmox 的支持都还算及时。选择标准很简单:看你所在地区和运营商。北方用清华和阿里云一般不错,南方有些网络访问中科大更快。脚本里我做了一个变量MIRROR,你可以自己改成顺手的镜像域名。
2.2 一键换源脚本的完整实现
换源部分的函数我拆成了几个独立动作:检测版本、备份现有源、注释企业源、写社区源。下面是核心代码。
detect_pve_version() { PVE_MAJOR=$(pveversion | grep -oP 'pve-manager/\K[0-9]+' | head -n1) case "$PVE_MAJOR" in 7) CODENAME="bullseye" ;; 8) CODENAME="bookworm" ;; 9) CODENAME="trixie" ;; *) echo "不支持自动识别版本: $PVE_MAJOR,请手动修改 CODENAME" exit 1 ;; esac } replace_apt_source() { MIRROR="https://mirrors.tuna.tsinghua.edu.cn/proxmox/debian" BACKUP_DATE=$(date +%Y%m%d%H%M%S) # 备份系统源文件 cp /etc/apt/sources.list "/etc/apt/sources.list.bak.${BACKUP_DATE}" 2>/dev/null || true # 备份并重写 pve-no-subscription 源 if [ -f /etc/apt/sources.list.d/pve-no-subscription.list ]; then cp /etc/apt/sources.list.d/pve-no-subscription.list "/etc/apt/sources.list.d/pve-no-subscription.list.bak.${BACKUP_DATE}" echo "deb ${MIRROR} ${CODENAME} pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list else echo "deb ${MIRROR} ${CODENAME} pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list fi # 注释企业源,避免 401 if [ -f /etc/apt/sources.list.d/pve-enterprise.list ]; then cp /etc/apt/sources.list.d/pve-enterprise.list "/etc/apt/sources.list.d/pve-enterprise.list.bak.${BACKUP_DATE}" sed -i "s|^deb https://enterprise.proxmox.com/debian/pve|#deb https://enterprise.proxmox.com/debian/pve|g" /etc/apt/sources.list.d/pve-enterprise.list fi # Ceph 源做同样的处理,仅当存在时 if [ -f /etc/apt/sources.list.d/ceph.list ]; then cp /etc/apt/sources.list.d/ceph.list "/etc/apt/sources.list.d/ceph.list.bak.${BACKUP_DATE}" sed -i "s|^deb https://enterprise.proxmox.com/ceph-|#deb https://enterprise.proxmox.com/ceph-|g" /etc/apt/sources.list.d/ceph.list fi }这段代码里有几个容易被忽视的点。
第一,grep -oP 'pve-manager/\K[0-9]+'是取pveversion输出中pve-manager/7.4-3的版本主号。\K表示从该位置开始匹配,前面的部分不会出现在结果里,这个写法比sed 's/.*pve-manager\/\([0-9]\+\)\..*/\1/'更直观,GNU grep 的-P选项在 Debian 上完全没问题。
第二,企业源的sed替换模式里我用了|作为分隔符,而不是常见的/。因为 URL 里本身带了很多/,再用/做分隔符就得各种转义,看着头疼。s|...|...|是 sed 允许的替代写法,处理 URL 场景非常合适。
第三,为什么重定向pve-no-subscription.list前要判断文件是否存在。因为某些 PVE 小版本里这个文件可能叫别的名字,或者压根没有,直接>会覆盖掉一个不相关的文件。先判断再创建,更安全。
2.3 换源后的验证和几个容易踩的坑
脚本执行完不要着急继续,先跑一遍apt-get update。看到源列表里没有报 401、路径中确实出现的是你设置的镜像域名,才算换到位。
我踩过的一个典型坑是重复的pve-no-subscription条目。有些镜像站教程让你在sources.list里直接加一行 PVE 源,之后 PVE 小版本升级又自动生成了sources.list.d/pve-no-subscription.list,最终apt update时会看到同一个仓库被定义了两次,虽然不致命,但偶尔会影响依赖解析。所以我建议的规范做法是:Debian 基础源留在/etc/apt/sources.list,PVE 相关源统一放在sources.list.d/下,脚本里重定向覆盖前额外cp一份备份,就是防止这种“文件里面已经有内容”的情况。
另一个坑是源文件里的components写法。Proxmox 官方源格式是deb https://xxx/debian bullseye pve-no-subscription,这个pve-no-subscription不是发行版代号,而是仓库组件名,不写或者写错都会导致 apt 找不到packages。所以无论怎么换镜像域名,这一项必须原样保留。
Ceph 源和普通 PVE 源不同,路径里通常带了 Ceph 版本代号,比如ceph-quincy。镜像站上是否同步了对应的 Ceph 组件,要看站点状态。如果不是做 Ceph 集群,最省事的就是把ceph.list里的企业源注释掉,不额外添加镜像源,这样apt update完全干净。
3. 关闭订阅提示:前端的那些小手脚
3.1 订阅弹窗是从哪里冒出来的
PVE 的 Web 管理界面是一个前端应用,由 pveproxy 这个服务提供。它会在你登录后向后端请求订阅状态,如果返回的是未订阅,前端 JS 就会在界面上层弹出一个提示框。这个提示框的逻辑不在后端,而在/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js这个文件里。
具体来说,文件里有一段类似的逻辑:判断返回的data.status是不是'Active',不是就弹出标题为No valid subscription的对话框。所以社区流行的方案,要么把判断条件改成永远为 false,要么直接把Ext.Msg.show那段替换成void({ ... }),让代码逻辑走到那里时什么都不执行。
需要注意的是,这个文件是 Ext JS 工具包的库文件,pveproxy 每次启动时会加载,但浏览器端也有缓存。修改文件后,必须重启 pveproxy 或者至少在浏览器里强制刷新,否则你看到的还是旧弹窗。
3.2 sed 替换方案与 restart pveproxy
我用的关闭提示方法,是在网上流传很广的sed -Ezi.bak一行流。它的原理是把proxmoxlib.js当作一个整体来处理,定位到Ext.Msg.show({ title: gettext('No valid sub这一段,在前面插入void({ //,把原来的调用变成注释掉一部分的无效代码。
close_subscription_tip() { JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" if [ -f "$JS_FILE" ]; then cp "$JS_FILE" "${JS_FILE}.bak.$(date +%Y%m%d%H%M%S)" sed -Ezi.bak "s/(Ext.Msg.show\(\{\s+title: gettext\('No valid sub)/void\(\{ \/\/\1/g" "$JS_FILE" systemctl restart pveproxy fi }这里最难解释的是sed参数。-E启用扩展正则,-z让 sed 按空字符而不是换行符来切分输入,也就是把整个文件当成“一行”来处理。-i.bak表示原地修改,同时生成一个.bak备份文件。后面跟着的正则里,\s+匹配空格和换行,gettext\('No valid sub是 PVE 前端未订阅弹窗标题的固定开头部分。前面插入void({ //后,Ext.Msg.show(...)就被包在注释里了,后面的代码逻辑虽然还能继续跑,但不会再弹窗。
不同 PVE 版本的正则匹配内容基本一致,因为No valid sub这个字符串从 7.x 到 9.x 一直没变过。如果你的版本较新,用上面命令后弹窗还存在,先别怀疑 sed,先执行grep -n "No valid sub" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js看看字符串还在不在。如果在,说明替换没匹配到,可能要微调正则里的空白符写法。
3.3 升级后弹窗复活的处理
关闭订阅提示有一个绕不开的问题:PVE 小版本升级时,/usr/share/下的文件可能会被重新覆盖,弹窗会跟着回来。这不是 bug,是包管理器在更新时恢复了系统文件的默认内容。所以这个操作不是一劳永逸的,我通常会在每次 PVE 升级后重新执行一遍脚本里的对应函数。
另外提醒一句,网上有些做法是直接删掉proxmoxlib.js里的整个弹窗函数,或者把文件改成空文件。非常不建议这么做,因为后续升级时会因为文件被修改过而报dpkg校验错误,甚至影响 pve-manager 包的升级。用sed -i做局部注释,保留文件整体结构,是最平滑的方式。
这里也把话说清楚:关闭订阅提示只是去掉了 Web 界面的弹窗提醒,并不会让你获得任何订阅用户专属的企业源权限。如果做生产环境、需要官方技术支持和稳定企业源,建议还是根据自己的授权情况评估。脚本里的这个功能更适合个人测试环境、实验环境自己用。
4. 硬件直通:IOMMU、VFIO 和直通脚本
4.1 直通前必须搞懂的底层逻辑
硬件直通,通俗讲就是把物理机上的一个 PCI/PCIe 设备,比如独立显卡、网卡、SATA 控制器,直接分配给某个虚拟机独占使用。要做到这一点,核心是 IOMMU 和 VFIO 两个机制。
IOMMU 是 CPU/主板上的一个地址翻译单元,作用类似小区物业的“独立车库钥匙”。默认情况下,所有设备的中断和 DMA 请求都要经过宿主内核统一调度,设备要访问虚拟机内存时,IOMMU 负责做地址翻译,避免虚拟机直接拿到物理内存地址造成隔离失效。Intel 平台管这个叫 VT-d,AMD 平台叫 AMD-Vi,都需要在 BIOS 里开启,同时要在内核启动参数里加上对应的intel_iommu=on或amd_iommu=on。
VFIO 则是用户态设备驱动框架。设备想直通进虚拟机,就不能再被宿主系统的原生驱动绑住。比如一块网卡默认被ixgbe驱动接管,你要直通给虚拟机,就得把网卡的设备 ID 告诉vfio-pci驱动,让它在开机时就把这块卡抢过去,等虚拟机启动时再映射进 Guest。
所以整个硬件直通配置,实际就三步:确认 CPU 支持并开启 IOMMU、把设备摘离原生驱动、把设备绑定给 VFIO 并更新 initramfs。步骤不复杂,但每一步都依赖前一步,漏掉任何一环,重启后都看不到期望效果。
4.2 一套兼容 Intel/AMD 的直通配置脚本
下面是脚本里直通模块的核心部分,我做了 CPU 厂商自动检测。
setup_passthrough() { BK_DATE=$(date +%Y%m%d%H%M%S) if grep -qi "GenuineIntel" /proc/cpuinfo; then IOMMU_PARAM="intel_iommu=on iommu=pt" else IOMMU_PARAM="amd_iommu=on iommu=pt" fi # 持久化加载 vfio 模块 cat > /etc/modules-load.d/vfio.conf <<EOF vfio vfio_iommu_type1 vfio_pci EOF # 判断当前引导方式是 GRUB 还是 systemd-boot if [ -d /sys/firmware/efi ] && [ -f /etc/kernel/cmdline ]; then cp /etc/kernel/cmdline "/etc/kernel/cmdline.bak.${BK_DATE}" sed -i "s/^root=.*/& ${IOMMU_PARAM}/" /etc/kernel/cmdline proxmox-boot-tool refresh else cp /etc/default/grub "/etc/default/grub.bak.${BK_DATE}" sed -i "s/^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"/GRUB_CMDLINE_LINUX_DEFAULT=\"\1 ${IOMMU_PARAM}\"/" /etc/default/grub update-grub fi # 更新 initramfs,让 vfio 模块进入初始内存盘 update-initramfs -u }这里有几个关键判断。grep -qi "GenuineIntel" /proc/cpuinfo是识别 Intel 和 AMD 最可靠的方式,比读取lscpu输出更直接。iommu=pt是额外优化参数,表示在设备直通时跳过不必要的 IOMMU 翻译,降低性能损耗。Intel 和 AMD 都可以加,但 AMD 平台只需要amd_iommu=on和iommu=pt,不需要iommu=on。
引导方式判断要特别说一下。PVE 8.x 之后,UEFI 安装环境默认使用 systemd-boot,此时内核参数写在/etc/kernel/cmdline,然后执行proxmox-boot-tool refresh同步到 EFI 分区。而传统 BIOS 或之前版本常用 GRUB,参数写在/etc/default/grub,执行update-grub。脚本里通过[ -f /etc/kernel/cmdline ]判断比较可靠,因为只有 systemd-boot 安装才会生成这个文件。
4.3 绑定设备 ID 与直通后的验证
直通前的最后一步,是把具体要直通给虚拟机的设备绑定到vfio-pci。这一步通常需要你提供设备的 vendor:device ID,也就是lspci -nn里看到的形如8086:10d3的编号。
bind_device_to_vfio() { echo "请输入 PCI 设备 ID,格式如 8086:10d3" read -r PCI_ID PCI_ID=$(echo "$PCI_ID" | tr '[:upper:]' '[:lower:]') if [ -z "$PCI_ID" ]; then echo "设备 ID 不能为空" return 1 fi echo "options vfio-pci ids=${PCI_ID}" > /etc/modprobe.d/vfio-pci.conf update-initramfs -u }这个modprobe.d/vfio-pci.conf文件会在内核加载vfio-pci模块时,自动将指定设备 ID 绑定到它身上。注意设备 ID 必须是小写,否则有些内核版本匹配不上。
重启之后,验证分几层。先看 IOMMU 是否开启:
dmesg | grep -e DMAR -e IOMMU能看到DMAR: IOMMU enabled或者类似输出,说明 IOMMU 正常工作。接着看设备是否被 vfio-pci 接管:
lspci -nnk | grep -A 3 -i "vga\|ethernet"如果输出里Kernel driver in use: vfio-pci,说明设备已经被成功摘离原生驱动。还可以查看 IOMMU 分组:
ls /sys/kernel/iommu_groups/ | wc -l分组数量越多,说明 IOMMU 拓扑越细,直通越灵活。如果只有一个分组甚至看不到任何分组,基本可以断定 IOMMU 没生效。
我还想提醒一个非常容易翻车的点:不要把装 PVE 系统的那块系统盘所在的 SATA 控制器直通出去。很多人看到主板上有两个 SATA 控制器,想直通一个给黑群晖或 NAS 虚拟机,结果把宿主系统盘也带走,一重启 PVE 直接失联。直通前务必用lsblk确认系统盘挂在哪个控制器下,只选择完全闲置的设备。
5. 整体执行流程与问题排查实录
5.1 把三件事拼成一个带菜单的脚本
单独的函数写好了,最后用一个交互菜单把它们串起来。Bash 的select结构天然适合做这种简单菜单,用户输入数字即选择对应功能。
show_menu() { PS3="请选择要执行的操作:" options=("换源" "关闭订阅提示" "硬件直通" "全部执行" "退出") select opt in "${options[@]}"; do case "$opt" in "换源") detect_pve_version replace_apt_source ;; "关闭订阅提示") close_subscription_tip ;; "硬件直通") setup_passthrough bind_device_to_vfio ;; "全部执行") detect_pve_version replace_apt_source close_subscription_tip setup_passthrough bind_device_to_vfio ;; "退出") break ;; *) echo "无效选项" ;; esac done } show_menu实际使用下来,我推荐的执行顺序是:先换源,再关订阅提示,最后做硬件直通。硬件直通放在最后是因为它需要重启机器才能验证,换源和关订阅提示在执行完后不需要重启,最多重启 pveproxy 或刷新浏览器,不打断当前工作。
另外,脚本整体要以 root 身份运行。PVE 的 shell 默认就是 root,但如果你是在普通用户下用sudo执行,要注意很多变量和命令(比如pveversion、proxmox-boot-tool)可能在sudo环境下找不到路径,最好在脚本开头加一句export PATH=$PATH:/usr/sbin:/sbin:/usr/local/sbin。
5.2 常见问题排查速查表
我在不同版本上反复执行这套脚本,把遇到最多的坑整理成了速查表,方便你对号入座。
| 问题现象 | 常见原因 | 处理方法 |
|---|---|---|
apt update报 401 错误 | pve-enterprise.list没有注释掉 | 执行换源脚本,或用#注释企业源 |
apt update提示仓库不存在 | 镜像源 URL 里components写错 | 确认是pve-no-subscription,不是pve |
| 网页端还是弹出订阅提示 | 浏览器缓存了旧 JS | 执行systemctl restart pveproxy,浏览器强制刷新 Ctrl+F5 |
pveproxy启动失败 | proxmoxlib.js被改坏了 | 用生成的.bak文件恢复,重新执行 sed |
重启后dmesg看不到 IOMMU | BIOS 里 VT-d/AMD-Vi 没开启 | 进 BIOS 开启对应选项 |
| 内核参数改了但重启没生效 | systemd-boot 没有执行 refresh | 执行proxmox-boot-tool refresh |
| 设备没被 vfio-pci 接管 | modprobe.d配置没生效或 ID 大小写不对 | 检查/etc/modprobe.d/vfio-pci.conf内容,重跑update-initramfs -u |
| 虚拟机配置直通后无法启动 | IOMMU 分组不完整或设备正在被宿主占用 | 查看/sys/kernel/iommu_groups/分组,调整设备位置 |
| PVE 升级后订阅弹窗又回来 | /usr/share下文件被覆盖 | 重新执行关闭订阅提示函数 |
5.3 我的一点点经验总结
这套脚本我最早是在 PVE 7.2 上写的,后来一路用到 8.4 和 9.0 预览版,中间改得最多的不是换源逻辑,而是引导方式判断和版本检测。PVE 版本迭代太快,尤其 8.x 到 9.x,很多教程里的路径已经开始失效,但只要你理解了背后的机制,遇到新版本也只需要微调变量名和路径。
一个实用的建议是:每台新服务器执行完脚本后,把生成的备份文件统一保留一段时间,不要手滑删掉。比如/etc/apt/sources.list.bak.20250612这种文件,系统跑稳定了可以清理,但至少保留最近一两次的。因为很多时候你改完配置,问题不是立刻暴露的,而是在下一次升级或重启后才出现,那时候再想找回原始文件,如果备份还在就非常省事。
硬件直通这个功能,脚本只负责把底层配置做好,真正直通到虚拟机还需要在 Web 界面里添加 PCI 设备。我之前犯过的一个错误是,直通了显卡但没给虚拟机配置显存,结果虚拟机开机能识别,但进系统后显卡驱动一直报错。后来才明白,直通显卡时需要先在虚拟机硬件配置里设置显存,并在启动参数里保留足够的 MMIO 空间。这不是脚本能覆盖的,所以完成脚本后,还是建议多看一遍 PVE 文档里对应部分的说明。
最后再分享一个小技巧:我习惯把换源时用到的镜像域名变量MIRROR单独提出来,放在脚本顶部,而不是藏在函数里。这样换一台服务器,如果当地访问清华源更快,改一行就行。脚本这种东西,越往后用越会发现,真正的维护成本不在命令本身,而在变量、路径和版本之间的兼容性。把这些细节处理好,一键方案才能做到真正省心。
本文还有配套的精品资源,点击获取