如果你的Mac突然停在白苹果或者问号文件夹,正常的桌面系统根本进不去,但一块移动硬盘里还存着你过去几年的所有文稿、照片和浏览器数据,这时候该怎么办?很多人的第一反应是找Time Machine备份恢复,但临时找一块装了Time Machine备份的硬盘并不现实。macOS恢复模式终端备份脚本,就是为了这个场景准备的——不需要安装任何软件,不需要联网,进入恢复模式打开终端就能直接跑,备份结果完整保留原本的目录层级,而且刻意避开了几个最常见的坑:源卷没挂载、备份盘上已经有同名目录、甚至把备份目标误选到了源盘里面。这篇文章把脚本的来龙去脉、设计取舍和实际踩过的坑完整拆给你。
1. 什么情况下会用到恢复模式终端备份?——先判断你的机器是否还有救
1.1 哪些故障场景值得进恢复模式尝试
恢复模式终端备份不是万能的,但适用范围比很多人想象中广。我遇到过至少三类场景,都靠这个方式把数据捞了回来。
第一类是系统引导损坏。表现为开机后一直卡在白苹果进度条,或者直接出现一个带问号的文件夹图标,说明系统找不到可引导的启动卷。此时系统分区可能已经挂了,但数据分区往往还是完好的,恢复模式依然能进入。第二类是升级或重装中途翻车,比如macOS大版本更新到一半断电、磁盘空间不足导致安装器失败,系统卡在一个半死不活的状态。第三类是桌面系统反复重启或进入登录界面后黑屏,但又没到彻底无法引导的程度,想在重装之前先把用户数据全部拖走。
进入恢复模式的方式很简单:Intel芯片的Mac开机时按住Command+R,Apple Silicon的Mac长按电源键,直到看到"正在载入启动选项",再点"选项"进入恢复环境。进入后菜单栏上找到"实用工具",点开里面的"终端",就能看到一个常见的bash/zsh命令行界面。
1.2 为什么Time Machine在这种场景下经常指望不上
很多人会问:Time Machine不是自带备份恢复吗?确实,如果有一块一直插着的Time Machine备份盘,恢复会方便得多。但现实往往是——备份盘不是每天都插着的,有些人甚至从来没有配置过Time Machine;就算有备份,最后一次备份可能停留在几天甚至几个月前,最近这段时间新增和修改的文件全丢了。更极端的情况是Time Machine备份盘本身跟着电脑一起损坏了,或者备份盘和源盘在同一个物理磁盘上(有些用户会把Time Machine备份目标设置到本机另一个分区,这在重装时同样不保险)。
恢复模式终端备份最大的价值,在于它绕开了所有"系统层面的依赖"。它不要求主系统能启动,不要求Time Machine存在,只需要你能进入恢复模式、数据卷能挂载、目标外置盘能被系统识别并写入,三条就够。这也是整个脚本设计的大前提:在最精简、最恶劣的环境里,把数据完整地搬到另一块物理盘上。
1.3 备份前的物理准备:外置盘的格式决定了脚本能否写入
进入恢复模式之前,最好先准备好外置硬盘,并且确认它的文件系统格式。恢复模式默认能读写的格式是APFS和HFS+,以及exFAT和FAT32。如果你在Windows环境下把移动硬盘格式化成NTFS,那么在macOS恢复模式下这块盘默认只能读、不能写,ditto备份脚本写进去一定会报错。
我在实际工作中见过太多次这种场面:用户到了恢复模式才发现唯一的移动硬盘是NTFS格式,最后只能到处找另一台Mac来格式化。所以建议在Mac还能正常开机的时候就提前把外置盘准备好,格式化成APFS或者exFAT。如果只是纯macOS环境使用,APFS最省心;如果这块盘还要在Windows和Mac之间来回倒数据,用exFAT更稳妥。另外记得给外置盘起个简单、不含空格的卷名,比如BackupDisk,后面写路径会省掉一大堆麻烦。
2. 恢复模式终端的"特殊体质":为什么脚本必须零依赖
2.1 恢复模式到底是一个什么样的系统环境
很多人以为恢复模式终端就是"一个能敲命令的窗口",跟正常系统里的终端差别不大。这是一个非常危险的误解。恢复模式实际上是一个独立的迷你系统(RecoveryOS),它从隐藏的Recovery分区或苹果服务器加载,根目录挂载的是一个只读的ramdisk镜像是。你在正常系统里熟悉的很多东西,这里统统没有。
最明显的区别是用户目录。恢复模式下,终端里的当前用户是root,不存在你平时那个带用户名的主目录,所以脚本里不能依赖$HOME、~这类变量,它们指向的路径在恢复模式下根本不存在。其次是工具链,这里只预装了一小部分基础工具:/bin/bash、/bin/ls、/bin/cp、/usr/bin/ditto、/usr/sbin/diskutil、/bin/df、/usr/bin/du、/usr/bin/find这些是基本可用的,但不要指望有Homebrew,不要指望有新版rsync,更不要指望有图形界面的文件管理器。正因为工具少到不能再少,脚本里每一个命令我都选恢复模式里确定存在的那一批。
2.2 ditto为什么是恢复模式下拷贝文件的最优选
恢复模式下拷贝文件有好几个候选命令:cp -R、rsync、tar、ditto。我最后选择了ditto,原因是它最贴近"Apple原生语义"。
cp -R可以递归复制目录,也能保留一些权限信息,但对macOS特有的资源分支(resource fork)、扩展属性(xattr)、ACL权限记录的支持并不完整。如果你备份的是照片图库、Pages文稿这类依赖元数据的文件,用cp复制出来的文件可能在正常系统里出现"已损坏"或无法打开的情况。
rsync在老版本macOS恢复模式中是存在的,但版本通常偏旧,而且恢复模式里可用的依赖库不全,某些选项执行到一半会报错。这个不确定性对备份来说是不能接受的。
tar可以把整个目录打包成一个归档文件,但它的致命问题是恢复单个文件不方便——你总不能在恢复模式下为了找一个文稿,把几百GB的tar包全部解压出来。而且tar包一旦中途损坏,后面所有的文件都跟着遭殃。
ditto是苹果自带的工具,恢复模式里几乎必然存在。它能够完整保留ACL、扩展属性、资源分支这些macOS文件系统独有的元数据,复制出来的目录层级和源目录完全一致,而且在目标目录已存在时会自动执行安全的合并复制,不会自作主张地嵌套一层同名目录。对"把整个用户目录原样搬到外置盘"这个需求来说,ditto就是最合适的底层工具。
2.3 路径里暗藏的坑:空格、中文、卷名飘忽不定
恢复模式下最常见的路径坑,就是卷名里带空格。苹果默认的启动卷叫"Macintosh HD",数据卷通常叫"Macintosh HD - Data",中间那个" - "就是两个空格加一个连字符。如果你不老实加上双引号,执行ditto /Volumes/Macintosh HD - Data /Volumes/BackupDisk,shell会把它拆成四个独立的路径参数,结果自然是一堆"No such file or directory"。
更隐蔽的问题在于卷名的"飘忽不定"。同一个数据卷,在不同的机器、不同的系统版本、甚至同一个系统不同时期的挂载名可能不一样。有些人把启动卷改名为"MacSSD",那数据卷就可能变成"MacSSD - Data"。如果只靠固定路径硬编码,换一台机器脚本就废了。所以脚本里不能只写死一个路径,需要在运行时检测/Volumes下实际挂载了哪些卷。在后面的脚本设计中,我会用自动发现加命令行参数覆盖的组合方式处理这个不确定性。
3. 脚本设计与实现:无依赖、保层级、避冲突三件事怎么落地
3.1 设计原则:一个脚本完成"检查-挂载-备份-验证"
写这个脚本之前,我就给自己定了几个硬性要求。第一,无依赖。整个脚本只使用恢复模式自带的基础工具,不要求安装任何第三方软件,不需要网络连接。第二,保层级。备份后的目录结构必须和源目录保持一致,用时间戳目录作为备份顶层,里面的Users/用户名/...相对路径原样保留,方便日后按路径找文件。第三,避冲突。这里说的冲突包括:目标盘不能是源盘本身或源盘的子目录,防止递归复制把源数据卷撑爆;目标目录如果已经存在,不能默默覆盖历史备份;源卷如果没挂载或者还被FileVault锁着,要在真正拷贝之前就给出明确提示,而不是等到ditto报错才一脸懵。
这三个原则看起来简单,但在恢复模式的特殊环境下,每一条都要用专门的代码去落实。
3.2 完整脚本清单:可以直接复制到终端跑的抄作业版
下面的脚本我起名叫recovery_backup.sh,在恢复模式终端里执行sh recovery_backup.sh即可运行。如果没有外置盘挂在默认位置,可以通过命令行参数覆盖:sh recovery_backup.sh "/Volumes/你的数据卷" "/Volumes/你的外置盘/Backups"。
#!/bin/bash # 文件名: recovery_backup.sh # 用途: macOS 恢复模式终端下的无依赖备份脚本 # 用法: sh recovery_backup.sh [源卷挂载点] [备份根目录] # 默认值可手动修改为你的实际卷名 SRC_VOL="/Volumes/Macintosh HD - Data" BACKUP_ROOT="/Volumes/BackupDisk/Backups" # 支持命令行参数覆盖默认值 if [ -n "$1" ]; then SRC_VOL="$1"; fi if [ -n "$2" ]; then BACKUP_ROOT="$2"; fi echo "========== 1. 检查源卷 ==========" if [ ! -d "$SRC_VOL/Users" ]; then echo "警告: 找不到 $SRC_VOL/Users, 尝试挂载 $SRC_VOL ..." diskutil mount "$SRC_VOL" >/dev/null 2>&1 if [ ! -d "$SRC_VOL/Users" ]; then echo "错误: 源卷挂载失败。" echo "请先在磁盘工具中解锁/挂载数据卷,再重新运行脚本。" exit 1 fi fi echo "找到源卷: $SRC_VOL" echo "========== 2. 检查备份根目录 ==========" if [ ! -d "$BACKUP_ROOT" ]; then echo "错误: 备份根目录不存在: $BACKUP_ROOT" echo "请确认外置盘已挂载,或通过参数指定其他路径。" exit 1 fi echo "备份根目录: $BACKUP_ROOT" echo "========== 3. 冲突检查 ==========" case "$BACKUP_ROOT" in "$SRC_VOL"/*|"$SRC_VOL") echo "错误: 备份根目录不能位于源卷内,否则会陷入递归复制。" exit 1 ;; esac echo "冲突检查通过" STAMP=$(date +%Y%m%d_%H%M%S) DEST="$BACKUP_ROOT/mac_${STAMP}" if [ -e "$DEST" ]; then echo "错误: 目标目录已存在: $DEST" exit 1 fi mkdir -p "$DEST" LOG="$DEST/backup.log" echo "========== 4. 预估源数据大小 ==========" SRC_SIZE=$(du -sk "$SRC_VOL/Users" 2>/dev/null | awk '{print $1}') if [ -z "$SRC_SIZE" ]; then SRC_SIZE=0; fi echo "源目录大小: $((SRC_SIZE/1024)) MB" | tee -a "$LOG" echo "========== 5. 检查剩余空间 ==========" FREE_SIZE=$(df -k "$BACKUP_ROOT" | awk 'NR==2 {print $4}') echo "目标盘剩余空间: $((FREE_SIZE/1024)) MB" | tee -a "$LOG" if [ "$SRC_SIZE" -gt "$FREE_SIZE" ]; then echo "错误: 剩余空间不足,无法继续。" | tee -a "$LOG" exit 1 fi echo "========== 6. 开始备份 ==========" echo "源目录: $SRC_VOL/Users" | tee -a "$LOG" echo "目标目录: $DEST/Users" | tee -a "$LOG" ditto "$SRC_VOL/Users" "$DEST/Users" >> "$LOG" 2>&1 RESULT=$? if [ "$RESULT" -ne 0 ]; then echo "错误: ditto 备份过程返回非零状态, 请检查日志。" exit 1 fi echo "========== 7. 备份后统计 ==========" SRC_COUNT=$(find "$SRC_VOL/Users" -type f 2>/dev/null | wc -l | tr -d ' ') DST_COUNT=$(find "$DEST/Users" -type f 2>/dev/null | wc -l | tr -d ' ') echo "源文件数: $SRC_COUNT" | tee -a "$LOG" echo "备份文件数: $DST_COUNT" | tee -a "$LOG" echo "" echo "========== 备份完成 ==========" echo "日志位置: $LOG" echo "建议安全弹出备份盘: diskutil eject 你的外置盘卷名" echo "在确认文件完好之前,请勿格式化源盘。"3.3 关键代码逐段拆解:脚本为什么可以这样跑
首先看源卷检查部分。[ ! -d "$SRC_VOL/Users" ]这个判断是整个脚本的第一道保险。因为恢复模式下,数据卷不一定会自动挂载到/Volumes下,特别是Apple Silicon机器上,APFS数据卷经常处于未挂载状态。如果直接跑ditto,大概率会得到一个"source path不存在"的报错。所以脚本先尝试diskutil mount "$SRC_VOL",挂载成功后再次检查。如果依然失败,说明这个卷要么卷名不对、要么是FileVault加密卷还没解锁,这时候脚本会明确提示去磁盘工具里处理。这个逻辑保证用户不会在瞎猜路径上浪费半小时。
冲突检查里用了一个case匹配:"$BACKUP_ROOT"/*|"$BACKUP_ROOT",专门拦截两种危险情况——备份根目录直接等于源卷,或者备份根目录位于源卷内部的某个子目录。为什么要这么写?如果用户把备份根目录设成了/Volumes/Macintosh HD - Data/Backup,ditto复制$SRC_VOL/Users时会把整个用户目录递归复制到源卷自己的子目录里,等于在同一个磁盘上做无限膨胀的自我复制,最后磁盘空间被写满是小事,整个数据卷被打包成一个互相嵌套的烂摊子才是大麻烦。这种错误在正常系统下很容易避免,但在恢复模式手忙脚乱的情况下非常容易发生。
防覆盖机制靠的是时间戳目录名。date +%Y%m%d_%H%M%S生成一个精确到秒的目录名,比如mac_20250214_153045,每次运行脚本都会落在不同的目录里,历史备份不会被覆盖。同时脚本检查$DEST是否已存在,如果存在就退出,这主要防的是用户在一分钟内重复运行脚本或者系统时钟异常导致的时间戳碰撞。备份目录独立还有另一个好处:如果一次备份失败,目标盘上只会多出一个不完整的mac_时间戳目录,不会破坏之前已经完成的备份。
大小预检部分用du -sk获得源目录的磁盘占用(单位是KB),再用df -k拿到目标盘的可用空间(同样以KB为单位),两者直接做整数比较。注意du -sk统计的是磁盘块占用,不是逻辑文件大小,所以实际备份出来的文件总字节数可能略小于这个数字,但用于空间判断是充分且保守的。如果源目录大小超过了目标盘可用空间,脚本直接退出,避免ditto拷贝到一半磁盘写满,留下一个残缺的备份目录。
备份主命令是ditto "$SRC_VOL/Users" "$DEST/Users"。这里有一个细节:源路径必须以Users结尾,目标路径也必须以Users结尾。ditto的复制语义是"把源目录本身的内容复制到目标目录",也就是当目标路径的最后一个目录名与源最后一个目录名相同时,它会直接填充内容而不是在目标下再嵌套一层同名目录。这样$DEST里就会出现一个和源完全一致的Users目录结构,层级保持得干干净净。备份过程中ditto的详细输出被重定向到日志文件$DEST/backup.log,这样终端窗口不至于被海量文件列表刷屏,事后排查时又能看到完整的拷贝记录。
备份后的统计环节用find ... -type f | wc -l统计源和目标两边的文件数量,做一个大致对比。恢复模式下,有些系统临时文件、缓存文件可能在备份过程中被系统自动写入或删除,所以两边文件数完全相等不是必须的,但数量级不能差太多。如果备份文件数比源文件数少了成千上万个,那就要警惕了。这个统计不能替代抽检,但至少能第一时间暴露明显的遗漏。
3.4 FileVault加密卷:脚本在什么时候需要人工介入
FileVault全盘加密是恢复模式终端备份绕不开的话题。如果你开启了FileVault,数据卷在恢复模式下看起来就是一个被锁定(locked)的APFS容器。diskutil mount命令不会弹密码框,你直接在脚本里执行挂载通常会失败。
这种情况下,处理路径有两条。一条是先在磁盘工具(Disk Utility)里点一下数据卷,输入密码挂载,然后再回到终端运行脚本;另一条是在终端里手动执行:
diskutil apfs list先看一下加密卷的Identifier,比如disk3s1,然后:
diskutil apfs unlockVolume disk3s1 -passphrase 你的密码如果不想在命令行里明文带密码,也可以只执行diskutil apfs unlockVolume disk3s1,它会提示你输入密码。解锁成功后,数据卷就会出现在/Volumes下,脚本也就能正常工作了。
这里我特别想提醒一句:恢复模式的这个界面里,密码输入是不显示回显的,输错了不会给太多提示,多试几次还没成功就先停下来,检查键盘布局和大小写锁定,别在慌乱中把密码永久试错到触发限制。
4. 实测验证与恢复演练:复制出来的数据到底能不能用
4.1 正常跑一遍脚本,标准输出长什么样
拿一台安装了macOS Monterey、开了FileVault的Intel MacBook Pro做测试,脚本执行时的标准输出大致如下:
========== 1. 检查源卷 ========== 找到源卷: /Volumes/Macintosh HD - Data ========== 2. 检查备份根目录 ========== 备份根目录: /Volumes/BackupDisk/Backups ========== 3. 冲突检查 ========== 冲突检查通过 ========== 4. 预估源数据大小 ========== 源目录大小: 48233 MB ========== 5. 检查剩余空间 ========== 目标盘剩余空间: 250000 MB ========== 6. 开始备份 ========== ========== 7. 备份后统计 ========== 源文件数: 312857 备份文件数: 312842这是一次比较顺利的备份。源目录47GB左右,包含31万个文件,整个过程大概持续了20多分钟。备份文件数比源文件数少了15个,属于正常波动——通常是某些临时文件、崩溃日志在复制过程中被系统清掉了。如果这个差值达到几百上千,就要怀疑是不是某个子目录因为权限或符号链接问题被跳过了。
4.2 备份完成后的第一轮验证,应该查什么
脚本跑完只是第一步,更重要的是确认备份数据的可用性。我每次备份完成后,都会在外置盘上做这么几件事:
第一,目录结构核对。执行ls -la "$BACKUP_ROOT/mac_时间戳/Users",确认里面能看到原本的用户名目录、Shared目录和.localized文件。如果用户名目录缺失,大概率是源卷本身有问题,要回到磁盘工具里再确认挂载情况。
第二,文件数量复核。用find "$BACKUP_ROOT/mac_时间戳/Users" -type f | wc -l和源盘对比,脚本本身已经做了这个输出,但等待片刻后我会再跑一遍,确保没有因为磁盘缓存写入滞后而产生误判。
第三,抽查关键目录。照片、文稿、桌面、下载这几个目录一定不能缺席。比如执行ls "$BACKUP_ROOT/mac_时间戳/Users/用户名/照片图库.photoslibrary"确认照片图库的包结构完整。包目录在文件系统里看起来是一个文件夹,其实是一个包含大量内部文件的文件包,如果ditto拷贝过程中断了,包目录会缺少内部文件,后续在正常系统里打开会提示"图库无法访问"。
第四,大小复核。用du -sh "$BACKUP_ROOT/mac_时间戳/Users"和源目录的du -sh对比,误差在几百MB以内都可以接受。如果目标盘大小比源目录小了十几个GB,那肯定有目录被漏掉了。
4.3 从备份恢复单个文件的最快捷径
恢复模式备份的最终目的,是让数据在新系统里重新可用。重装完macOS、创建好新用户之后,恢复单个文件非常简单,直接在终端里用ditto逆向操作即可:
ditto "/Volumes/BackupDisk/Backups/mac_20250214_153045/Users/旧用户名/文稿" "$HOME/文稿"这里有个细节要注意:如果新系统的用户名和旧用户名不一样,备份里的顶层用户名目录名和当前$HOME的名字就对不上。这时候不要图省事把整个Users/旧用户名全部拷贝覆盖到新用户目录,最好按子目录逐项恢复——文稿、图片、下载、桌面这些用户产生的数据直接拷,Library/Application Support这类含应用数据的大目录也可以拷,但系统自己生成的Library/Caches、Library/Preferences这类不建议整体覆盖,否则可能把新系统的设置搞乱。
另外,从外置盘往内置盘拷贝时同样建议用ditto而不是Finder拖拽。这么做不仅保留了文件权限和扩展属性,也避免了某些文件因为特殊元数据被Finder拒绝复制的情况。拷贝完以后,立刻打开几个关键文件验证一下,再正常关机。
5. 踩坑记录与脚本边界:哪些问题脚本解决不了
5.1 外置盘是NTFS格式怎么办
这是现场翻车率最高的一类问题。恢复模式下系统对NTFS分区是只读的,你执行df -k /Volumes/NTFS盘可能一切正常,但ditto一旦开始写入就会疯狂报错Read-only file system。
处理办法只有两个:一是在Mac还能正常开机的时候提前把外置盘格式化成APFS或exFAT;二是找另一台Mac或Windows电脑,把外置盘上的旧数据挪走再重新格式化。千万不要在恢复模式里对着一块NTFS盘做"原地修改格式",没有命令行工具能无损转换文件系统格式,折腾半天还是得找别的机器。这也是为什么我在文章开头反复强调备份盘要提前准备,绝不能在系统已经进不去的时候才想起格式化。
5.2 备份过程中出现超大单个文件导致"空间判断失效"
脚本里的空间预检基于du -sk的磁盘占用,这通常足够可靠,但有一个例外:如果你的用户目录里存在一个超大的单个文件,比如虚拟机镜像、视频剪辑工程或iOS设备整机备份,占用空间可能达到几十GB甚至上百GB。du -sk统计的是整个目录的总占用,df -k检查的是目标盘可用空间,这两个数在大多数情况下是准确的,但APFS文件系统在写入时会有快照、元数据开销,实际可用空间可能比df报的数字下降得更快,导致ditto写到后期突然碰到磁盘满。
对付这种场景,我通常会在备份前额外执行一条命令,专门排查特大文件:
find "$SRC_VOL/Users" -type f -size +10G -exec ls -lh {} \;这条命令把大于10GB的单个文件全部列出来,你先做到心里有数。这些大文件如果在备份中单独拷失败了,后续只补拷这一个文件,成本要小得多。
5.3 备份中途被Ctrl+C中断、合盖睡眠,盘上留下残缺目录怎么办
恢复模式下备份几十GB的数据,中途有一定概率出意外。最常见的操作失误是手滑按了Ctrl+C,或者在等待备份时下意识按了一下电源键合盖,让机器进入睡眠状态。中断后的情况是:目标盘上留下了一个不完整的mac_时间戳目录,里面有部分文件,但没有备份日志里的"备份文件数"统计。
处理方式很直接:把这个不完整目录整体改名,比如加一个_broken后缀,然后重新运行脚本,生成一个新的时间戳目录再来一遍。为什么要改名而不是直接删掉?因为备份过程中可能有部分有价值的文件已经落盘了,万一源盘在第二次运行时彻底挂掉,这个不完整目录里的文件还能救一部分;直接删掉就等于放弃了这部分成果。等第二次备份完整跑完、确认源数据已经完整复制后,再回头清理这些带_broken后缀的残留目录也不迟。
5.4 用户目录和系统目录的取舍:哪些内容是只需要备份的
整个/Volumes/Macintosh HD - Data/Users是可以整体备份的,但实际从实用性出发,用户目录里真正需要在意的是以下几个子目录:
Desktop、Documents、Downloads、Pictures、Movies、Music:用户产生的数据,优先级最高Library/Application Support:大量应用的数据存储于此,比如浏览器收藏夹、密码库、聊天记录存档Library/Mail:邮件客户端的全部本地邮件Library/Safari:浏览器历史、书签、打开的标签页Library/Keychains:钥匙串,包含各种网站和应用的账号密码,如果你不想重装后重新输入所有密码,这个目录非常关键
反过来,系统级的/System、/Library、/Applications目录不需要备份。重装完系统之后,应用全部重新下载安装即可,系统目录更是会被安装器重新生成。即使你备份了/Applications,里面很多应用的框架依赖、后台服务在裸拷贝状态下也不能正常工作,与其浪费空间不如直接放弃。这个边界从一开始就在脚本里体现——源路径只指向$SRC_VOL/Users,天然避开了系统目录。
5.5 弹出备份盘的正确姿势,以及"备份完就拔"的惨痛教训
备份完成后,从终端安全弹出外置盘,有个细节。直接执行diskutil eject /Volumes/BackupDisk通常就能成功弹出,但如果提示Resource busy,先检查一下终端当前的工作目录是不是还停在外置盘里面:
cd / diskutil eject /Volumes/BackupDisk把工作目录切回根目录之后,大部分busy问题都能解决。如果还不行,有可能是某些后台进程(比如Spotlight索引)还在读盘。在恢复模式这种精简环境下,这个概率不高,但你可以在终端里再等十几秒重试一次。
我见过不少用户备份成功后就迫不及待拔掉外置盘,结果第二天发现某个关键目录漏掉了,或者备份盘里的文件在新系统下打不开,只好重新进恢复模式再跑一遍。正确做法是:备份完成、日志和文件数统计都对得上之后,再等一个操作周期,找一台能正常开机的电脑,插上备份盘打开几个文件确认正常,然后再把备份盘收起来。多花这几分钟,换来的是一整块硬盘数据的心安。
6. 恢复模式备份之外的两个实用补充
6.1 如果脚本跑完一轮,目标盘目录意外出现了权限属主错乱
这种情况不多见,但一旦出现就要重视。具体表现是:备份盘插回正常系统后,某些文件的属主变成了root,普通用户无法修改。根因通常是恢复模式终端里的ditto以root身份执行复制,如果源文件本身的属主在目标文件系统上无法映射,就会落到root名下。
这不是脚本的bug,而是文件系统元数据在不同卷之间复制时的固有现象。应对方法是在新系统里可以批量修正属主:
sudo chown -R 你的用户名:staff "/Volumes/BackupDisk/Backups/mac_时间戳/Users/你的用户名"如果只是在备份盘上查看、拷贝个别文件,属主错乱影响不大;如果要整体把备份目录作为新用户主目录迁移回去,这个修正步骤就很有必要。
6.2 一台Mac上备份,另一台Mac上恢复,怎么保证路径不冲突
有些场景下,备份盘会被拿到另一台Mac上去恢复。此时新机器的用户目录名很可能和旧机器的不同。就算用户名一样,登录密码偏好设置、钥匙串配置也可能完全不兼容。我的建议是:不要直接覆盖新机器整个用户目录,而是新建一个临时用户或者临时目录,把备份数据逐项导入到文稿、图片等指定位置。这样可以最大程度避免因用户GID(组ID)不一致导致的文件权限归属混乱,也避免把旧系统的缓存和偏好设置带进新环境。