如何用cp命令模拟rsync的文件同步功能并规避坏扇区引发的硬盘故障?
如何用cp命令模拟rsync的文件同步功能并规避坏扇区引发的硬盘故障?
我完全懂你的糟心经历——rsync碰到坏扇区不仅会直接停住,还可能触发硬盘的重分配机制,让原本只是有点坏道的盘彻底掉链子,这事儿搁谁身上都头疼。你想用cp来替代rsync,同时保留它的同步核心功能,这个思路非常务实,我来帮你捋清楚怎么操作。
首先先看看你现有的cp命令:
cp -v -dR --copy-contents -f -n --preserve=mode,ownership,timestamps
先拆解下这些参数的作用,顺便指出核心问题:
-v: verbose模式,能看到复制过程,没问题-d:保留链接不 Dereference,同时保留链接属性,符合同步需求-R:递归复制目录,这个也没问题--copy-contents:复制特殊文件(比如设备文件、管道)的内容,而不是只复制属性,适合你要完整同步文件的需求-f:当目标文件无法打开时(比如权限锁、被占用),删除它再重试复制,这个参数很实用,不是只用于追加,别误解它-n:不覆盖现有文件——这是和rsync逻辑冲突的地方!rsync的同步核心是更新有变化的文件,而-n直接跳过所有已存在的文件,完全达不到你想要的“更新文件”效果--preserve=mode,ownership,timestamps:保留权限、所有者、时间戳,完美匹配rsync的属性同步需求
接下来解决你两个核心诉求:
1. 让cp模拟rsync的“增量更新”逻辑
cp本身没有rsync那样自动对比文件差异(时间戳、大小、内容)的功能,所以我们得用shell脚本配合基础命令来补上这个逻辑。下面是一个实用的脚本,能实现“只复制目标不存在、源文件更新、大小不同或内容不同的文件”:
#!/bin/bash # 替换成你的源目录和目标目录 SOURCE="/mnt/source-disk" DEST="/mnt/backup-disk" # 递归遍历源目录的所有文件(包括特殊文件),用null字符分隔避免文件名含空格的问题 find "$SOURCE" -type f -print0 | while IFS= read -r -d $'\0' src_file; do # 获取文件相对于源目录的路径,保证目标目录结构和源一致 rel_path="${src_file#$SOURCE/}" dest_file="$DEST/$rel_path" # 创建目标文件的父目录(如果不存在) mkdir -p "$(dirname "$dest_file")" # 判断是否需要复制:目标不存在/源更新/大小不同/内容不同(cmp超时则认为内容不同,规避坏扇区卡住) if [ ! -f "$dest_file" ] || [ "$src_file" -nt "$dest_file" ] || [ "$(stat -c%s "$src_file")" -ne "$(stat -c%s "$dest_file")" ] || ! timeout 15 cmp -s "$src_file" "$dest_file"; then echo "Updating: $src_file -> $dest_file" cp -v -d --copy-contents -f --preserve=mode,ownership,timestamps "$src_file" "$dest_file" fi done
这个脚本的逻辑和rsync的增量同步非常接近:
- 用
-nt判断源文件是否比目标文件新 - 对比文件大小,处理你提到的预分配文件(大小相同但内容不同的情况)
- 用
timeout + cmp来快速对比内容,碰到坏扇区导致cmp卡住时,直接超时判定为内容不同,执行复制(避免整个脚本卡壳)
2. 规避坏扇区导致的硬盘故障恶化
你提到的硬盘状况急转直下,很大概率是因为硬盘在读取坏扇区时自动触发了重分配机制——它会尝试把坏扇区的数据移到备用扇区,这个过程可能会让硬盘负载飙升,甚至损坏更多扇区。解决办法是:
- 只读挂载源硬盘:在复制前,把源盘挂载为只读模式,这样硬盘不会尝试重分配坏扇区,减少进一步损坏:
(把mount -o ro /dev/sdX /mnt/source-disk/dev/sdX替换成你的源硬盘设备名,比如/dev/sdb1) - 如果某个文件碰到坏扇区导致cp卡住,可以单独用
dd跳过坏扇区复制:dd if="$src_file" of="$dest_file" conv=noerror,sync bs=4Mconv=noerror表示碰到错误继续复制,sync表示用空字节填充坏扇区的位置,这样不会卡住,也能尽量保留能读取的内容。
最后调整你的cp命令
如果不需要严格的增量更新,只是想覆盖那些需要更新的文件,直接去掉-n参数就行,但这样会复制所有文件(不管有没有变化),效率会低很多,所以更推荐上面的脚本方案。
备注:内容来源于stack exchange,提问作者Estatistics
相关产品推荐
相关产品推荐

