Linux文件夹复制全攻略:从cp到rsync的深度实践
1. 复制的底层逻辑先搞懂Linux文件系统再动手很多新手用Linux复制文件夹第一反应就是cp -r能拷完就行。但如果只是停留在“能用”这个层面迟早会在权限、软链接、硬链接、大目录、增量同步这些环节上栽跟头。我见过不少运维新人一个cp -r把整个网站目录从测试机拷到生产机结果权限全乱、软链全断最后花了大半天也修不回来。所以在动手之前我建议你先花两分钟想一个问题复制文件夹到底复制的是什么表面上是把一个目录下所有文件和子目录“复制”到另一个位置。但Linux底下文件夹并不是一个装文件的“容器”而是一个目录项dentry结构它记录着一堆“文件名 - inode”的映射。你看到的每一个文件其实是指向inode的链接inode里才存着文件的元数据权限、属主、时间戳、数据块位置等。所以复制文件夹本质上是在目标位置重新建立一套“目录项 inode 数据块”的映射关系。这一层认知特别关键因为很多复制工具的差异恰恰就体现在“怎么重建这套关系”上cp默认直接新建inode把源文件数据逐字节写入新的数据块然后在目标目录里创建新的目录项。所以复制出来的文件和源文件的inode编号完全不同。cp -l/cp -s硬链接/软链接模式不复制数据内容而是在目标位置创建一个指向源inode的硬链接或者一个指向源文件路径的软链接。rsync默认按大小和时间戳判断跳过那些“看起来没变”的文件只拷贝有变化的部分配合--checksum则按内容校验。tar管道方式先把整个目录的结构和数据打包成字节流再传输到目标位置解包这种方式在保留权限、属主、ACL、稀疏文件属性时通常最稳。所以不要急着背命令先根据你的需求问自己三个问题复制的目标位置是在同一台机器上还是跨主机是需要完整复制包括权限、属主、时间戳还是只把“文件内容弄过去”就够是一次性全量复制还是以后还要定期同步增量回答完这三个问题工具选型就清晰了本地小规模复制用cp本地大规模备份用rsync跨主机安全传输用rsyncssh保留完整元数据优先用tar管道。这篇文章里的每一段几乎都是围绕这三个问题的选择展开的。2. cp命令全套解析从入门到常用的十个变体2.1 cp -r 的局限性为什么远程复制不能直接用cpcp是Linux用户最先接触的复制命令但也是最容易被滥用的一个。先看最基础的理解cp复制普通文件和目录。cp /path/to/source/file /path/to/dest/ cp -r /path/to/source/dir /path/to/dest/dir其中-r表示递归复制目录。这个参数对新手来说是“记忆点”只要复制目录就无脑加-r。但如果你只记到这一步有四个坑很快会找上你。第一个坑是权限。cp默认会读取源文件权限复制到目标时会“尽量保留权限位”但目标目录如果有setgid位或者你所在目录有ACL复制结果就可能和你预期的不一样。更重要的是cp在复制时不保留文件的时间戳除非加-p这会让备份失去“何时创建、何时修改”的元信息。第二个坑是符号链接。cp -r默认会跟随符号链接把软链指向的目标文件内容也复制过来而不是保留链接本身。这意味着如果源目录里有一个软链接指向/etc/nginx/nginx.conf复制过去之后你会得到一个独立的普通文件链接关系断了。备份场景里这通常不是你想要的结果。第三个坑是硬链接。cp默认不会保留硬链接结构如果源目录里有两个文件名指向同一个inode复制之后它们会变成两个独立的文件各自占用磁盘空间。第四个坑是稀疏文件。数据库或虚拟机的磁盘镜像文件往往是几GB的逻辑大小但实际只占用几百MB的物理空间。cp默认不做稀疏化检测会老老实实地把逻辑大小整个写入占用大量磁盘空间。那怎么解决记住cp的这几个参数基本就够日常用了cp -a # 等价于 -dR --preserveall最大程度保留链接和元数据 cp -p # 保留权限、属主、时间戳 cp -d # 不跟随符号链接保留链接本身 cp -l # 创建硬链接而非复制数据 cp -s # 创建符号链接而非复制数据 cp -u # 仅当源文件比目标文件新时才复制 cp -n # 不覆盖已存在的目标文件 cp -v # 输出每个文件的复制过程方便查看 cp -i # 覆盖前交互确认好习惯 cp --sparsealways # 强制稀疏文件检测与还原cp -a几乎是本地完整复制的默认首选因为--preserveall保存了权限、属主、时间戳、上下文、ACL等所有能保存的属性。如果你在复制一个目录后还要直接拿到生产环境去用用-a会比-r稳妥得多。2.2 实战对比cp -r、cp -a、cp -u 的差异我用一个具体的实验来展示差异。假设我有个目录/data/web里面包含/data/web/ ├── index.html ├── images/ │ └── logo.png ├── link_to_config - /etc/nginx/nginx.conf # 符号链接 └── archive.tar.gz # 大文件分别执行三条命令cp -r /data/web /backup/web_r cp -a /data/web /backup/web_a cp -ur /data/web /backup/web_inc复制完成后检查ls -l /backup/web_r/link_to_config如果用的是-r你会发现link_to_config变成一个普通文件大小跟/etc/nginx/nginx.conf一样。如果用的是-alink_to_config仍然是符号链接指向原路径。再看时间戳。-r复制出来的index.htmlmtime是复制那一刻的时间-a复制出来的mtime保留源文件的时间。如果这个目录是要作为软件包发布、需要依赖make判断依赖关系时间戳错了会让增量编译失灵。-u则在你反复同步时特别有用。比如你第一次用cp -a全量复制后来源目录里只改了index.html这时执行cp -ur /data/web /backup/web_a会只复制比目标目录更新的文件避免全部重拷。我的建议是cp -r只能在“压根不在乎元数据、局域网小规模复制、目标目录是全新空目录”这几类场景下用。只要涉及备份、环境迁移、发布交付一律用cp -a起步。3. rsync增量同步企业里最常用的文件夹复制工具3.1 rsync核心参数的取舍与组合rsync是Linux运维工具箱里的常青树。它在本地和远程都能用核心价值在于增量同步只传输变化的数据块而不是每次把整个文件夹都拖一遍。基础的本地同步命令如下rsync -avz /data/web/ /backup/web/这个命令里几个参数的含义要拆开讲-aarchive归档模式等价于-rlptgoD递归复制、保留符号链接、权限、时间戳、属主、组、设备文件和特殊文件。大部分场景下有-a就足够处理“保留元数据”这件事。-vverbose输出同步过程能看到哪些文件被传输哪些被跳过对排查问题非常关键。-zcompress传输时压缩适合网络带宽紧张的跨主机复制。本地复制时不建议加-z白白消耗CPU速度反而更慢。企业级的同步脚本里我通常会在此基础上组合出这样一条核心命令rsync -avz --progress --partial --delete /source/dir/ userremote-host:/target/dir/--progress显示每个文件的传输进度。大文件多的时候看到进度条心里踏实也能及时发现卡住的是哪个文件。--partial保留部分传输的文件断点续传。如果不加这个参数传输中断后已传一半的文件会被直接删除下次从头再传。--delete删除目标端存在但源端已经不存在的文件让两边的目录结构完全一致。不过这个参数有风险配合-ndry-run先模拟执行是铁律。我见过不止一次有人把--delete写进正式命令后忘记先演练结果目标目录里积累了半年的历史备份文件被一夜清空。所以只要你用到--delete永远先跑一遍模拟模式rsync -avzn --delete /data/web/ /backup/web/-ndry-run只输出“将要做什么”不会真正执行多花几秒钟看一下输出结果能避免很多灾难。3.2 本地增量备份脚本的完整设计结合上面的参数我提供一个我自己在用的本地增量备份脚本思路。这个脚本做两件事第一用rsync做镜像同步第二用--backup参数保留被覆盖或删除的旧文件。#!/bin/bash # 功能将 /data/project 增量同步到 /backup/project # 使用直接执行该脚本或加入 crontab 定时运行 SOURCE_DIR/data/project/ BACKUP_BASE/backup DATED_DIR$BACKUP_BASE/$(date %F_%H-%M-%S) LATEST_LINK$BACKUP_BASE/latest LOGFILE$BACKUP_BASE/rsync_$(date %F).log # 1. 先做一次普通镜像同步到 latest 目录 rsync -av --delete $SOURCE_DIR $LATEST_LINK/ $LOGFILE 21 # 2. 把当前状态硬链接复制为带时间戳的快照 cp -al $LATEST_LINK $DATED_DIR # 3. 清理超过30天的快照 find $BACKUP_BASE -maxdepth 1 -type d -name 20* -mtime 30 -exec rm -rf {} \;第二步里的cp -al是关键。-a保留元数据-l创建硬链接而不是复制数据内容。由于rsync已经把latest目录中的文件同步成最新的了这里用硬链接生成快照目录时基本不占额外磁盘空间却能形成一份“该时间点的完整文件视图”。这种“rsync同步 硬链接快照”的组合是我个人认为性价比最高的本地备份方案既省钱又不丢历史版本。3.3 跨主机同步的SSH隧道细节跨主机的rsync你只需在目标位置加上userhost:前缀前提是两台机器都装了rsync并且SSH能连通。rsync -avz --progress /data/web/ deploy192.168.1.100:/var/www/html/这里有一个容易踩的坑如果远端路径结尾有斜杠绝对路径语义是什么这里需要特别小心rsync -avz source/ userhost:/target/把source目录的内容放到远端/target目录里面。rsync -avz source userhost:/target/把source这个目录本身放到远端/target目录里面。我第一次用rsync做网站发布时就因为在目标路径开头多写或少写了一个斜杠导致目录层级多了一层前端资源全部404。现在我的习惯是本地源路径统一加斜杠远端目标路径统一以/结尾这样语义最清晰。还有一个性能相关的经验当目录里文件数超过几万尤其是大量小文件时rsync默认的“逐个文件扫描”会非常慢。这时候可以开启增量扫描rsync -avz --delete --fuzzy --inplace /data/web/ userremote:/var/www/--inplace让目标文件在原位置更新不走“临时文件改名”的流程对单个大文件的覆盖更新会快很多缺点是如果中途断了目标文件可能处于半新半旧的状态所以适合文件较大且能容忍这种情况的场景。--fuzzy允许rsync在目标目录里寻找相似的旧文件作为基准减少传输量。跨主机还要注意防火墙和端口。SSH默认走22端口如果远端改了SSH端口这样指定rsync -avz -e ssh -p 2222 -i /home/user/.ssh/id_rsa /data/web/ userremote:/backup/-e参数专门用来指定远程shell这里给ssh传了端口和密钥文件。用密钥认证代替密码认证既能免交互也为后续定时任务cron做准备。4. 完整实操从需求梳理到自动化定时同步4.1 需求场景我如何设计一套网站目录发布系统为了让前面的工具和方法串联起来我以一个具体场景为例一台应用服务器代码需要从开发机发布到测试环境每天凌晨2点自动执行一次全量增量备份。需求拆解一下开发机上的目录/home/dev/app/需要同步到测试机192.168.1.110的/srv/app/。同步完成后需要在测试机上保留昨天的文件版本方便回滚。整个过程要支持断点续传万一半夜断网下次还能继续。必须有日志第二天早上能看是否成功。基于这个需求我不可能只用cp因为有跨主机和增量需求所以核心选择是rsyncSSH。为了方便密码管理我事先在开发机上生成一对密钥把公钥加到测试机的authorized_keys里并限制只用密钥登录。4.2 从零到一的发布脚本与crontab配置先写发布脚本/home/dev/bin/deploy.sh#!/bin/bash # 网站目录增量发布脚本 APP_SOURCE/home/dev/app/ REMOTE_HOST192.168.1.110 REMOTE_USERdeploy REMOTE_PATH/srv/app/ REMOTE_BACKUP/srv/backup/$(date %F_%H-%M-%S) SSH_PORT2022 SSH_KEY/home/dev/.ssh/id_ed25519 LOG_FILE/home/dev/logs/deploy_$(date %F).log # 创建今日日志目录 mkdir -p /home/dev/logs echo [$(date %F %T)] 开始部署 $LOG_FILE # 1. 在远端先做一个备份用于回滚 ssh -i $SSH_KEY -p $SSH_PORT $REMOTE_USER$REMOTE_HOST \ cp -a $REMOTE_PATH $REMOTE_BACKUP $LOG_FILE 21 # 2. 用 rsync 增量同步主程序 rsync -avz --progress --partial \ -e ssh -i $SSH_KEY -p $SSH_PORT \ --delete \ $APP_SOURCE $REMOTE_USER$REMOTE_HOST:$REMOTE_PATH $LOG_FILE 21 # 3. 保留最近7天的远端备份 ssh -i $SSH_KEY -p $SSH_PORT $REMOTE_USER$REMOTE_HOST \ find /srv/backup -maxdepth 1 -type d -name 20* -mtime 7 -exec rm -rf {} \; $LOG_FILE 21 echo [$(date %F %T)] 部署结束 $LOG_FILE把这个脚本加入crontabcrontab -e写入0 2 * * * /home/dev/bin/deploy.sh看到这里你可能有个疑问为什么先SSH到远端做cp -a备份而不是直接把今天同步的版本在远端留着因为--delete会把源端不存在的文件删除如果测试机开启了修改比如临时测试改动这些改动会在同步时被抹掉。所以我在同步前先用cp -a全量保存一份当前状态再执行增量同步。这样做的好处是任何时候出问题都能从/srv/backup/里找回前一版。4.3 复制后如何验证完整性同步完成不代表万事大吉我习惯在脚本末尾加一段校验。轻量级方案在源端和目标端分别统计文件数量和总大小然后对比。echo 源端统计信息 find /home/dev/app -type f | wc -l du -sh /home/dev/app echo 目标端统计信息 ssh -i $SSH_KEY -p $SSH_PORT $REMOTE_USER$REMOTE_HOST \ find $REMOTE_PATH -type f | wc -l; du -sh $REMOTE_PATH如果数量一致且大小误差不大基本可以判断复制成功。如果还不放心可以加-c参数开启校验和模式rsync -avzc --delete /home/dev/app/ userremote:/srv/app/-c强制校验每个文件的内容校验和能发现“大小和修改时间一致但内容被篡改”的文件。代价是每次同步都要全量读取文件算校验和扫描速度会明显下降。对于代码发布这类场景我觉得-c成本偏高只在文件损坏高发的场景例如磁盘即将故障用。5. 权限、ACL与特殊文件的复制最容易翻车的角落5.1 为什么复制过去权限全乱了我见过太多人用cp复制完网站目录然后出现403 Forbidden第一反应是服务配置错误查了半天才发现是文件权限从644变成了600或者目录权限从755变成700。权限乱的根源在于cp默认行为里的权限继承逻辑当目标文件已存在时cp会保留目标文件的权限当目标文件不存在时它复制源文件的权限位但忽略属主和组。如果你是以root身份复制目标文件的属主变成了root如果你是以普通用户身份复制目标属主就是当前用户。要彻底避免权限问题记住两点第一复制时用-p或者-a保留权限位和属主信息。第二如果源目录里的文件属主不是当前用户普通用户怎么复制都会丢属主这时要么用root执行要么复制完再用chown纠正。cp -a /data/web /backup/web_backup chown -R www-data:www-data /backup/web_backup5.2 ACL、xattr和SELinux上下文的保留技巧普通网站目录可能用不到ACL访问控制列表但只要你接触多租户服务器、共享目录或者SELinux强制开启的系统cp -a也未必能覆盖一切。查看文件是否设置了ACLgetfacl /data/web/index.html如果返回里有user:alice:rwx这种条目说明有扩展ACL。用cp复制默认会保留ACL吗cp -a会因为它等价于--preservemode,ownership,timestamps,context,xattr,links,all其中就包含xattr和ACL。但如果只用cp -rACL就丢了。SELinux上下文这块更隐蔽。在RHEL/CentOS系系统上如果一个文件被复制到错误的安全上下文服务可能无法读取。建议复制后检查ls -Z /data/web/index.html如果system_u:object_r:httpd_sys_content_t:s0这一串上下文不对用restorecon恢复restorecon -Rv /data/web/如果你希望复制时就保留上下文cp还不一定靠谱更稳的方式是用rsync -X保留扩展属性rsync -avX /data/web/ /backup/web/-X会单独把xattr属性同步过去在启用了SELinux、且需要精确复制安全上下文的场景下这条命令比cp -a更可控。5.3 特殊文件设备文件、FIFO和Socket的复制原则设备文件、FIFO管道、Socket文件这些不是普通的数据文件用cp复制会有问题。设备文件比如/dev/nullcp默认按普通文件处理可能会卡死或复制出错误的文件类型。使用cp -a时--preserveall包含--preservelinks和设备的属性能识别设备文件但意义不大——因为设备文件绑定的是内核驱动复制到另一台机器上基本无效。FIFO管道文件cp会尝试从管道里读取数据如果另一端没有写者命令会一直阻塞。正确的做法是用rsync -a它会在目标端重新创建这层结构不会去读管道内容。Socket文件这是最需要警惕的。比如/var/run/mysqld/mysqld.sock如果你把这整个目录复制备份正常情况下rsync和cp会跳过socket文件但不同版本行为不完全一致。备份这类动态目录时我建议在rsync命令里显式排除socket文件最稳rsync -av --exclude*.sock --exclude/run/ /var/run/ /backup/run_backup/总结一下复制一个包含特殊文件的目录时要么用rsync -a会保留类型不复制内容要么用tar管道它能准确记录文件类型并在目标端重建。不要用裸cp -r它在这类场景下行为不可控。6. 性能优化大目录与小文件批量复制的提速方案6.1 为什么几百万个小文件复制特别慢一个目录里文件数量上百万、单文件只有几KB的场景在日志目录、缓存目录、代码仓库里太常见了。这种场景下cp -a的速度会惨不忍睹——几小时都拷不完。原因有两层。第一层是inode遍历的开销每处理一个文件系统都要做一次目录项查找、一次inode读取、一次数据块分配。文件越小这个固定开销占比越高。第二层是cp的单线程模型它一个接一个地复制不会并行处理两个文件。针对第二层可以用find xargs并行复制find /data/small_files -type f -print0 | xargs -0 -P 8 -I {} cp -a {} /backup/small_files/-P 8表示同时跑8个cp进程能明显提升吞吐。但要注意这种方式的目录结构复制不完整因为find只列出了文件目录本身可能没有被创建。所以更合理的做法是先用rsync传结构再用并行cp传数据。我自己在最极端的情况下用过第三种方案先tar打包再解包。这个方案对小文件批量迁移最有效因为tar顺序读取数据块磁盘寻道开销最小tar -C /data/small_files -cf - . | tar -C /backup/small_files -xf -实测在机械硬盘上这个组合能比cp -a快数倍。但它的一条重要限制是管道模式下如果目标端出错你没办法断点续传只能重新再来。所以我通常把它用在“一次性迁移”场景而不用在“定期同步”场景。6.2 网络传输瓶颈如何判断是网络慢还是文件系统慢跨主机的rsync如果传输速度上不去先别急着加并行参数慢的根源往往是网络协议栈或磁盘I/O。我在排查时按这个顺序做# 1. 先测纯网络带宽 iperf3 -c 192.168.1.110 -t 10 # 2. 看rsync传输时CPU和磁盘I/O状态 iostat -x 1如果iperf3测出的带宽接近千兆或万兆理论值说明网络不是瓶颈问题在文件系统I/O。如果iperf3也很慢那就要检查网卡、交换机链路、TCP窗口大小了。网络正常的场景下rsync提速可以从几个方向入手加-z在瓶颈是带宽时有效但如果瓶颈是CPU或磁盘I/O压缩反而拖慢速度。加大TCP缓冲区某些内核参数可以调整但涉及全局修改我一般只在有明确需求的主机上做比如通过-e ssh -c aes128-ctr选择更轻量级的SSH加密算法降低加解密消耗。拆分任务把大目录按子目录拆成多份用多个rsync实例并行跑避免单个任务卡在某个超大的文件中。监控具体文件用--progress确认是不是某个特定文件拖慢了整体进度。有一次我排查了很久发现是某个log文件持续在增长导致rsync永远同步不完最后在命令里加--exclude*.log才解决。6.3 本地复制也慢的隐藏原因磁盘空间与inode耗尽还有一种情况复制过程中突然报错No space left on device但df -h一看磁盘空间明明还有。这多半是inode耗尽了。df -i查看inode使用率df -hi /backup如果IUse%接近100%那再怎么删大文件也腾不出空间因为inode就是这个文件系统能承载文件数量的上限。解决办法是清理目录里的小文件或者换一个inode数量更多的文件系统重新挂载。复制大量文件的场景中目标磁盘的文件系统类型也会影响性能。ext4在大量小文件场景下表现中规中矩xfs在并行写入和大量文件场景下通常更好而ZFS和btrfs因为启用了校验和与快照文件多的时候CPU开销会明显上升。如果是临时中转目录用tmpfs内存盘往往比磁盘更快但注意数据断电即失。在计划一个日常备份任务前我强烈建议你先跑一次小规模试复制观察目标磁盘空间和inode变化rsync -av --delete /data/test/ /backup/test/ df -h /backup df -i /backup试复制能让你提前发现空间不足、inode不足、权限不符这些问题避免在正式备份的深夜才发现坑。7. 常见问题与排查技巧实录7.1 复制中断和残留文件如何安全重试复制大目录的过程中随时可能因为网络断开、目标磁盘满、SSH超时而中断。最怕的不是中断本身而是中断后不知道已经复制了多少、从哪里继续。两个建议帮助应对这种情况第一rsync天然支持重试幂等。中断后直接重新执行同样的命令它不会重复传输已经完成且校验一致的文件。所以不要中途去删掉部分复制的文件保留现场重新跑一遍即可。rsync -avz --partial --progress /data/web/ userremote:/backup/第二如果目标目录残留大量半截文件比如之前用cp拷贝中断的先清理还是先覆盖我的习惯是先清理一部分不完整的文件再重新跑rsync。比如根据大小判断把目标目录里大小为0或明显小于源文件的可疑文件删掉再执行同步。稳妥起见可以先用find列出这些文件find /backup -type f -size 0 -delete7.2 符号链接断链复制后链接指向不存在的路径符号链接的路径是绝对路径时复制到新环境后很容易断链。例如/data/web/link_to_config - /etc/nginx/nginx.conf你把它复制到另一台机器上如果目标机器上/etc/nginx/nginx.conf不存在链接就打不开。这种问题的根源不在复制工具而在设计方案。如果你希望链接跟着内容一起迁移应该复制链接指向的实体文件而不是链接本身如果你希望保留链接的“链接到此路径”语义那就必须保证目标环境的路径结构和源一致。实际处理中有两个办法同步前用readlink检查链接的目标确认目标路径是否也存在于接收端。复制后用find -L找出断链文件find /backup/web -type l ! -exec test -e {} \; -print把断链的软链接单独列出来然后人工确认是补路径还是重建链接。7.3 复制后中文文件名乱码编码处理思路文件名乱码多数是因为源系统和目标系统的字符集设置不一致。源文件名的字节是以UTF-8编码存储的但接收端终端用GBK解析显示就乱。注意这只是“显示”乱码文件名的实际字节并没有被破坏。正确做法是保证两端都使用统一的字符集。检查系统编码locale如果输出里LANG不是en_US.UTF-8或zh_CN.UTF-8这种UTF-8结尾文件系统层面就可能出现交互问题。在复制命令前临时设置export LANGzh_CN.UTF-8 rsync -avz /data/上传目录/ userremote:/data/upload/还有一种情况是文件名里包含解释性特殊字符比如换行符或奇怪的Unicode字符这类文件在rsync输出日志里会出现奇怪的换行导致日志文件错乱。处理方式是用-0参数配合find来精确定位或者干脆用convmv把非标准文件名转成标准UTF-8convmv -f gbk -t utf-8 --notest /path/to/dir/7.4 权限拒绝时的排查顺序复制时提示Permission denied大多数人的第一反应是sudo加满但这掩盖了真正的问题。我的排查顺序是这样的先确认当前用户对源目录是否有读取权限ls -ld /source/dir。再确认对目标目录是否有写入权限touch /target/dir/.write_test。如果源目录里某个子目录或文件不可读sudo也不会自动带上需要检查具体权限位和ACL。如果复制到NFS或CIFS挂载的远程目录还要确认挂载选项里是否启用了rw和user权限。一个参考命令链namei -l /data/web/subdir/filenamei能显示路径每一级的权限属性方便定位到具体哪一层卡住。很多“我明明有权限”的情况其实是路径中间某一级目录的x权限不够。比如/data是drwx------普通用户根本进不去/data/web自然复制不了。7.5 常见问题速查表场景推荐命令注意点本地完整复制目录保留所有元数据cp -a src dst保留权限、时间戳、ACL不跟随软链接本地复制目录忽略元数据cp -r src dst跟随软链接可能复制到链接指向的实体本地增量同步rsync -av --delete src/ dst/目标路径加斜杠明确是“目录内容”跨主机安全传输rsync -avz -e ssh -p 2222 src/ userhost:/dst/远端路径结尾加斜杠防止层级错乱大量小文件迁移tar -C src -cf - . | tar -C dst -xf -速度最快但无断点续传保留SELinux安全上下文rsync -avX src/ dst/需root权限且两端支持xattr定期备份保留历史快照rsync cp -al组合硬链接快照空间占用小校验复制完整性rsync -avzc --delete src/ dst/全量校验和扫描慢但结果可靠每个运维都会形成自己习惯性的复制命令组合不用强求统一。但有一点我想强调不要在线上环境临时发明命令尤其是涉及--delete、跨主机、多级目录的操作。先在测试目录里把命令跑通用-ndry-run看输出结果确认无误后再执行正式命令。这个习惯救了我太多次。8. 复制之外文件夹同步的方案对比与选型建议8.1 cp、rsync、tar、unison、syncthing怎么选Linux下的复制与同步工具不止cp和rsync。这里把一些常见方案的特性放一起对比帮助你按场景选型。工具增量传输双向同步跨平台元数据保留适用场景cp否否否取决于参数本地一次性简单复制rsync是单向通过SSH跨平台优秀本地/远程单向同步、备份tar 管道否否是优秀大批量一次性迁移unison是是是优秀双向同步解决两边都有改动的场景syncthing是是是一般多设备实时同步P2P协议unison适合两边都有修改、且需要双向合并的场景比如笔记本和服务器之间的工作目录同步。不过它依赖的有点多配置门槛稍高。syncthing更适合个人文件实时同步但它不擅长保留Linux的复杂元数据服务器场景慎用。8.2 备份还是同步概念上别搞混最后想多说一句“备份”和“同步”的区别。很多人把rsync同步当作备份看似一样实则天差地别。同步是把两边的文件状态保持一致。源目录里误删了一个文件同步后目标目录也会删掉。如果那个文件是唯一副本那同步就是一场灾难。而你如果做的是备份应该保留历史版本误删也能恢复。所以在设计备份策略时请把同步和备份分开看同步保证多台机器上的当前状态一致用rsync -av --delete。备份保留某个时间点的完整快照用“rsync 硬链接快照”或带时间戳的完整复制。我自己在实际操作中坚持一个原则所有涉及--delete的同步任务执行前必须有“昨天的快照”兜底。没有回滚能力的同步就像没有安全气囊的车看着能跑出事就是大事。写到这里Linux文件夹复制这件事应该算说明白了。从cp到rsync从权限到性能从本地到跨主机核心就是把“复制”这个概念拆开看数据块、元数据、目录结构、增量变化。下次你在命令行面前想复制一个文件夹时先用三秒钟想清楚自己要的是哪一层再决定用哪个工具。这样处理起来既快又稳还不太会翻车。