拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

macOS恢复模式终端备份:无依赖、保层级、避冲突的应急方案

macOS恢复模式终端备份:无依赖、保层级、避冲突的应急方案 前阵子朋友一台 Mac 升级系统时突然断电再开机就卡在进度条一半怎么都进不去桌面了。还好他手边有块移动硬盘我借机进恢复模式用终端把资料一份份捞了出来。他看着我敲命令有点意外原来 Mac 进不了系统还有这样一个“急救窗口”macOS 恢复模式里的终端是系统彻底起不来时最后一扇门。很多人在搜索“macos重装”、“macos镜像iso下载”其实第一步应该想清楚系统能不能重来是小事硬盘里的资料丢不得。所以这次把我常用的那套备份脚本完整梳理一遍。它最大的特点就是标题这六个字无依赖、保层级、避冲突。不装任何工具不破坏目录结构也不会把备份盘本身卷进去。适合在系统崩溃、磁盘异常、重装前手动救数据也适合不想依赖时间机器的朋友应急用。1. 为什么需要在恢复模式终端手动备份1.1 什么样的故障会逼你进恢复模式常见的情况有这几种系统升级到一半断电或死机开机后一直转圈磁盘工具提示“该卷宗需要修复”但进系统就崩溃再就是自己准备抹盘重装想把用户目录先完整拖出来。先说清楚恢复模式到底是什么。它是 macOS 内置的一个独立维护环境不是一个完整系统但自带磁盘工具、终端、重新安装 macOS 等入口。在 Intel Mac 上通常开机按住 CommandR在 Apple Silicon 上长按电源键然后选择“选项”进入。这个环境里的终端就是本文操作的地方。很多人一听“终端备份”就发怵其实没必要。恢复模式里的终端没有乱七八糟的配置shell 就是 bash 或 zsh工具也都是系统自带的。你不需要会 Bash 脚本编程只要能复制粘贴命令、看懂路径和报错就行。1.2 为什么时间机器和迁移助理不够用数据备份有很多路径但真到了进不了系统的阶段可选方案就窄了。时间机器需要在系统设置里开启而且正常情况下它是后台自动备份。如果你从来没有配过外置盘或者根本没做过时间机器备份那这时候它帮不上忙。就算做过备份系统进不去时也要先进恢复模式通过“从时间机器恢复”来找备份这本身也依赖网络和备份盘格式正常。迁移助理更挑条件它要求新旧两台 Mac 都能正常启动旧机器还能跑系统才能用“迁移助理”导出。到了连桌面都进不去的阶段迁移助理基本等于废了。终端手动备份反而最直接只要能进入恢复模式、能挂载外接存储、能读取源卷宗就可以一条条命令把数据拷走。它不依赖网络、不依赖登录密码如果没开 FileVault、不依赖系统完整性。这也是应急场景下最靠谱的一条路。1.3 “无依赖、保层级、避冲突”到底指什么“无依赖”是指脚本只用 macOS 恢复模式自带的基础命令。常见的是 rsync、ditto、cp、mkdir、date、df、du不依赖 Homebrew不依赖 Python不依赖任何“你平时装了但恢复模式下并没有”的第三方工具。这点很关键因为恢复模式是个精简环境很多你以为存在的工具其实都没有。“保层级”是说要保留源目录完整结构。比如你要备份/Users/apple/Documents下的内容恢复后仍然是Documents里那些文件子目录不散。实际操作中最怕的就是备份出来一堆散文件恢复时根本不知道原先是放在哪里的。“避冲突”则更体现经验。恢复模式下所有卷都挂在/Volumes下如果备份时不小心把整个/Volumes当源目录那你的备份目标盘本身也会被当成数据复制进去形成“自我复制”空间很快会被耗尽。另外还有路径名带空格、同名目录覆盖、目标盘格式不支持文件名等问题都是冲突源。后面的脚本就是围绕这三个问题来设计的。2. 脚本设计背后的几个关键决策2.1 备份工具选 rsync 还是 dittomacOS 自带两种适合目录级拷贝的工具rsync 和 ditto。两者都能保留层级但侧重点不同。rsync 是 Linux 系常用的增量同步工具macOS 恢复模式里一般自带一个较老的版本。它的优势是支持--exclude排除规则、断点续传虽然这里不讨论远程、保留权限和硬链接-aAX参数。缺点是如果系统镜像版本太老rsync 对某些新文件元数据的处理会保守一些。ditto 是 macOS 原生的文件拷贝工具不需要 rsync 就能运行对资源分叉、扩展属性和旧文件头兼容性更好。它没有排除规则一旦指定源目录就是整个目录结构照搬。想跳过某个子目录就得先把它排除在外或者从上层的更精确路径开始备份。我的做法是脚本里先判断有没有 rsync有就用 rsync没有就落到 ditto。这样两个环境都能跑不需要你在恢复模式现场纠结。判断代码很简单if command -v rsync /dev/null 21; then echo 使用 rsync else echo 使用 ditto fi这不是偷懒而是保证“无依赖”落地的直接方式。现场最怕的其实是命令行能用但是缺一个关键参数导致备份读到一半失败。2.2 保层级的路径写法有那么一点讲究rsync 对路径末尾的斜杠非常敏感。这个细节坑过不少人。rsync -aAX /Users/apple/Documents /Volumes/Backup/会把Documents这个目录本身放进目标目录结果是/Volumes/Backup/Documents/...。rsync -aAX /Users/apple/Documents/ /Volumes/Backup/则会把Documents里的内容直接铺到目标目录根下结果是/Volumes/Backup/...层级少了一层。实际需求往往是我想要一个带名字的备份根目录。所以脚本里先创建带时间戳的目标目录再把源目录内容同步进这个目录同时源路径末尾保留/避免多套一层。举个例子DST_DIR/Volumes/Backup/backup_20250412_153000 mkdir -p $DST_DIR rsync -aAX /Users/apple/Documents/ $DST_DIR/这样备份结果就是/Volumes/Backup/backup_20250412_153000/下直接是 Documents 里的文件。恢复的时候把这个目录里的东西放回Documents即可。如果你想让目标目录里还能看出“原来这层是 Documents”那源路径末尾就不加/让目录本身被包含进去。两种情况都是保层级区别只在于你要保留多少原文信息。2.3 怎么避开“自我复制”的深坑恢复模式终端里的路径组织方式和日常桌面完全不同。日常系统启动后你的系统盘挂载点是/外置盘在/Volumes/xxx。但在恢复模式里原来的系统盘一般挂在/Volumes/Macintosh HD - Data外置盘也是/Volumes/xxx所有卷宗平级排列。这个布局最容易出现的错误就是盲目备份整个/Volumes下的内容。一旦你把/Volumes当作源目录备份目标盘必然也在/Volumes里于是它一边接收数据一边又把自己当成源数据被扫描复制这几乎是一次无底洞式的循环拷贝。脚本里我做了两层防护第一层使用${1:-}读取命令行参数时明确要求你提供精确的源目录而不是简单默认成/Volumes。如果没有给参数脚本直接退出并提示用法。第二层单独加一个检查块判断源目录路径是否包含了目标备份盘的路径部分case $SRC_DIR in *$DST_ROOT*) echo [错误] 源目录包含备份目标盘存在自我复制风险 exit 1 ;; esac注意这个判断在极端情况下会有误报比如源目录恰好叫/Volumes/Backup且目标盘也叫Backup但比起那种循环复制到磁盘写满的后果我宁可在这个环节卡得更严格。另外还有一个日常常见的冲突点同名目录互相覆盖。如果目标目录已经存在同名文件夹rsync 默认会往里面继续合并。为了不让多次备份缠成一团脚本里每次跑都自动生成一个新的backup_时间戳目录从根上避免同名覆盖问题。2.4 为什么是 bash 而不是别的恢复模式下没有图形界面给你装包管理器所以脚本老老实实选 bash。macOS 自带的/bin/bash是 3.2 版本语法老但不影响我们用的这些基础功能。我也没有用 Python因为恢复模式里/usr/bin/python3在最新几个系统版本上有可能不一定存在或者版本飘忽。更重要的是bash 脚本只需要一个文本文件就能跑不需要解释器去加载任何第三方库。这一点非常符合“无依赖”的定位。如果你连脚本文件都不方便带进去那也简单在终端里手动逐条敲命令就行。脚本只是为了把这一串命令固化下来方便反复使用属于“可复现”而不是“必须依赖”。3. 完整脚本与实现细节3.1 脚本全文下面是我目前常用的完整版本保存为macos-recovery-backup.sh#!/bin/bash # 恢复模式终端备份无依赖、保层级、避冲突 # 用法: # bash macos-recovery-backup.sh 源目录 备份目标根目录 # 示例: # bash macos-recovery-backup.sh /Volumes/Macintosh HD - Data/Users/apple/Documents /Volumes/MyBackup set -u SRC_DIR${1:-} DST_ROOT${2:-} echo 恢复模式备份脚本 echo 源目录: ${SRC_DIR:-未指定} echo 备份根目录: ${DST_ROOT:-未指定} if [ -z $SRC_DIR ] || [ -z $DST_ROOT ]; then echo 错误: 必须指定源目录与备份根目录 echo 示例: echo bash macos-recovery-backup.sh \/Volumes/Macintosh HD - Data/Users/apple/Documents\ \/Volumes/MyBackup\ exit 1 fi # 避免把备份目标盘自身当作源数据 case $SRC_DIR in *$DST_ROOT*) echo 错误: 源目录包含了备份目标盘存在自我复制风险 exit 1 ;; esac if [ ! -d $SRC_DIR ]; then echo 错误: 源目录不存在: $SRC_DIR exit 1 fi if [ ! -d $DST_ROOT ]; then echo 警告: 备份根目录不存在尝试创建: $DST_ROOT mkdir -p $DST_ROOT || exit 1 fi DST_DIR$DST_ROOT/backup_$(date %Y%m%d_%H%M%S) mkdir -p $DST_DIR echo 本次备份目录: $DST_DIR # 空间估算 SRC_SIZE$(du -sh $SRC_DIR 2/dev/null | awk {print $1}) DST_FREE$(df -h $DST_ROOT | awk NR2 {print $4}) echo 源目录体积约: ${SRC_SIZE:-未知} echo 目标盘剩余空间约: ${DST_FREE:-未知} if command -v rsync /dev/null 21; then rsync -aAX \ --exclude .Trash \ --exclude .Spotlight-V100 \ --exclude .fseventsd \ $SRC_DIR/ $DST_DIR/ STATUS$? else ditto -rsrc $SRC_DIR $DST_DIR STATUS$? fi if [ $STATUS -eq 0 ]; then echo 备份完成: $DST_DIR echo 建议用 ls -la 抽查关键目录内容。 else echo 备份过程中可能遇到错误请检查上面的输出。 fi3.2 入参、判断与自动建目录脚本前几行其实已经把“避冲突”做掉了。set -u的意思是脚本里只要引用了未定义变量就立刻报错退出。这避免因为变量名拼错而把文件拷贝到莫名其妙的路径。这不是必须的但对应急脚本来说宁可早失败也不要晚失败。SRC_DIR${1:-}和DST_ROOT${2:-}这种写法是让脚本在两个参数都没传的情况下不会因为$1不存在而直接终止而是把变量设为空字符串然后往下走到检查逻辑输出一个清晰的中文用法提示。为什么参数设计成两个而不是把源目录硬编码到脚本里因为不同人的数据目录不一样有人要备份Documents有人要备份整个用户目录还有人要专门备份某个项目文件夹。做成参数现场指定脚本一份通用。检查了源目录和目标盘之后脚本使用date %Y%m%d_%H%M%S生成一个精确到秒的时间戳目录作为本次备份的独立目录。这个设计我不打算改它直接解决了多次备份同名冲突的问题。3.3 APFS 卷宗与 FileVault 加密卷的处理较新的 macOS 版本采用 APFS 分层卷宗结构常见的是系统卷和数据卷分离。比如你平时看到的“Macintosh HD”在恢复模式下可能显示为“Macintosh HD - Data”这样一个名字。备份用户数据时源目录应该指向数据卷下的路径而不是只读的系统卷。如果你的数据卷启用了 FileVault恢复模式下不会自动解密挂载。先用diskutil list找到对应卷宗标识符然后执行类似这样的命令手动解锁diskutil apfs list diskutil apfs unlockVolume /dev/disk3s1执行后终端会提示输入该卷宗的口令。解锁成功后才能看到卷宗挂载点也就是你在/Volumes下找到“Macintosh HD - Data”这个名字。这部分虽然不是脚本本身做的但是脚本运行的前置条件。你在恢复模式下如果发现源目录不存在大概率不是脚本问题而是卷宗还没解密挂载。3.4 核心备份命令逐段解释脚本里的备份命令主体是这行rsync -aAX \ --exclude .Trash \ --exclude .Spotlight-V100 \ --exclude .fseventsd \ $SRC_DIR/ $DST_DIR/-a是归档模式表示递归拷贝并保留权限、属主、时间戳、符号链接等属性。-A保留 ACL 访问控制列表。-X保留扩展属性。这三个参数合在一起基本能最大限度还原一个真实的用户目录。--exclude排除掉一些没有必要备份的本地缓存和系统索引目录。.Spotlight-V100和.fseventsd属于索引类临时数据备份了反而可能在恢复后造成各种奇怪问题。.Trash是废纸篓一般不需要把它里的东西备份出来。如果现场环境没有 rsync则使用 dittoditto -rsrc $SRC_DIR $DST_DIR-rsrc参数表示保留资源分叉。ditto 会把$SRC_DIR以及它内部的整个结构复制到$DST_DIR目标目录不存在时会自动创建。注意 ditto 没有排除机制所以备份范围取决于你给的源路径。理论上如果你指定~/Library这种巨大又复杂的目录ditto 会完整照搬。4. 实操流程从开机到完成校验4.1 进入恢复模式打开终端芯片类型不同进入恢复模式的操作不太一样。Intel 机型开机时按住 CommandR直到出现苹果 Logo 和进度条。如果之前设置了固件密码会先要求输入。Apple Silicon 机型先按一下电源键开机然后长按电源键不放直到屏幕出现“正在载入启动选项”再点击右下角的“选项”按钮然后选择“继续”。进入恢复界面后顶部菜单栏找到“实用工具”点开里面就有“终端”。启动终端后shell 默认的工作目录是/然后我们可以开始查看磁盘状态。4.2 确认磁盘挂载状态让外接盘可被访问我先执行diskutil list看看所有卷宗和外接盘的标识符。接着执行ls /Volumes看现在的挂载点名称。如果你的移动硬盘没有出现在列表里不用急着重启试一下在“磁盘工具”里手动挂载或者用diskutil mount。例如我的备份盘叫MyBackup执行ls -la /Volumes如果已经挂载应该能看到/Volumes/MyBackup。此时外接盘的格式建议是 APFS 或 Mac OS 扩展日志式。如果是 exFAT也能用但文件名特殊字符、资源分叉可能会有兼容隐患后面会专门说。接下来确认源数据卷。以常见的“系统盘用户目录”为例在恢复模式下源路径通常长这样/Volumes/Macintosh HD - Data/Users/apple/Documents注意引号。路径里有空格终端解析时必须用双引号包住否则会被拆成多个参数。4.3 运行脚本实测示例把脚本放到一个方便的位置。比如我把 U 盘里的脚本文件放到备份盘根目录然后执行bash /Volumes/MyBackup/macos-recovery-backup.sh /Volumes/Macintosh HD - Data/Users/apple/Documents /Volumes/MyBackup如果你身边没有脚本文件也可以把脚本内容直接粘贴进终端执行。技术上没有任何区别只是长文本粘贴时注意一次粘贴完整避免中断。运行后脚本会输出源目录体积、目标盘剩余空间然后进入拷贝阶段。rsync 在恢复模式下默认不输出实时进度如果你的数据量大可能会觉得“卡住了”。这时候先不要盲目中断给它一点时间。想看详细输出的可以把-aAX改成-aAXv但生产环境我建议保持安静避免大量文件列表刷屏。如果中途出现Input/output error或者No space left on device说明目标盘空间不够或磁盘不稳定需要换更大的备份盘重新跑。4.4 验证备份结果不要急着拔盘备份完成后我至少做三件事。第一看目录层级是否正确ls -la /Volumes/MyBackup/backup_20250412_153000第二抽查关键文件是否能读取比如对某个大文件执行md5或shasum和源文件对比。恢复模式自带这些校验命令只是输出比较慢建议只抽查几个大文件。第三确认结束后用diskutil unmount /Volumes/MyBackup卸载备份盘再拔线。这一步很多人忽略导致数据还没落盘就被拔出损坏。5. 常见问题速查与避坑实录5.1 目标盘没有挂载或看不到最常见的原因就是移动硬盘在恢复模式下没有被自动挂载。打开“磁盘工具”看左侧有没有外置卷宗。有的话点一下“挂载”按钮。没有的话检查一下数据线是不是纯充电线很多移动硬盘附赠的线只能供电不能传数据。换一个支持数据传输的接口或线缆再试。如果移动硬盘本身之前是 Windows 用的 BitLocker 加密盘macOS 恢复模式下通常无法直接读取。需要提前在正常系统里把数据拷出或格式化。5.2 FileVault 加密卷宗无法读取这是新手最容易懵的地方。你在终端里ls /Volumes发现看不到“Macintosh HD - Data”但磁盘工具里明明有卷宗。原因就是卷宗已加密且未解锁。解法是用diskutil apfs list查出数据卷的 identifier类似/dev/disk3s1然后执行diskutil apfs unlockVolume /dev/disk3s1并输入密码。解锁后卷宗就会被挂载到/Volumes。如果你的 Apple ID 开启了“恢复密钥”而不是本地密码请确保手里有恢复密钥。没有这个任何方法都救不回数据卷里的内容。5.3 备份途中中断或提示资源忙终端备份过程中不要频繁开关 Finder 里的磁盘工具窗口也不要同时打开“磁盘工具”里的“急救”功能去修复同一个卷宗。恢复模式下同一块盘的并发读写比正常系统更挑剔容易触发“Resource busy”报错。真的中断了也别慌重新运行脚本它会生成一个全新的时间戳备份目录。你上一次没拷贝完的目录就留着确认没有遗漏后再手动清理。我这里还有个独家建议如果备份的是几十 TB 级别的素材库不要指望一次性跑完。可以把脚本里的源目录拆细按大类分批备份比如设计稿一个任务、照片一个任务、代码仓库一个任务。每次备份的目录都是独立时间戳哪怕后期发现某批缺失重跑那一批就可以。5.4 恢复时路径对不上很多人备份完了恢复时却犯迷糊明明备份的是Documents恢复后却找不到那些文件。原因就是忽略了脚本设计里的“保层级”关系。脚本里源路径为/Users/apple/Documents备份目录为backup_时间戳那么恢复后内容会出现在backup_时间戳/下面相当于原来Documents里的所有内容都被放在这个目录里。恢复时你应该把backup_时间戳/里面的内容放回/Users/apple/Documents而不是把整个backup_时间戳目录直接拖进去。你可以在恢复的时候先在目标位置建好Documents文件夹再把备份内容移动进去。这样层级就和原来完全一致。5.5 exFAT 格式盘备份后文件名出现问号如果备份盘是 exFAT 格式遇到 macOS 独有字符或文件名中的特殊字符可能出现“?”或者无法创建的情况。exFAT 毕竟不是 macOS 原生日志文件系统对 Unicode 和文件权限的支持没有 APFS 那么完整。所以备份盘尽量用 APFS 或 Mac OS 扩展日志式。如果一定要跨平台exFAT 也能做临时应急但备完要紧数据后尽快转到 APFS 存储。这个细节平时不注意关键时刻能坑掉一整个目录的文件。5.6 经验速查表现象可能原因解决办法ls /Volumes看不到外接盘未挂载或数据线只供电磁盘工具挂载换数据线/接口源目录找不到FileVault 加密卷未解锁diskutil apfs unlockVolume备份过程中空间不足目标盘太小换更大目标盘或拆细备份目录备份结果没有子目录层级源路径末尾多/少写斜杠按脚本参数格式重跑保留目标时间戳目录文件名变成?目标盘是 exFAT改用 APFS/HFS 备份盘中文文件名乱码终端编码问题查看locale恢复模式下通常无碍重点检查目标盘格式最后再说一点个人体会这套脚本我自己用下来最大的感受是越简单的方案越可靠。恢复模式这个环境里没有图形动画没有“正在复制”的进度条也没有人提醒你剩余空间还有多少能依赖的只有清晰的路径、完整的命令和一点耐心。我后来每次给别人的 Mac 做重装前救援都会先跑一遍类似脚本顺便把移动硬盘的格式、数据线、电源都确认一遍。这些准备看起来琐碎但真的到了开机都困难的时候每一件都能决定数据能不能救回来。能学到的最有价值的东西不是某一条 rsync 参数而是“备份动作本身要提前规划”这个习惯。就算平时没用时间机器至少也该知道恢复模式终端里有一扇窗——不进桌面照样能把资料搬出去。
返回列表