尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Linux文件夹复制实战:从cp到rsync的进阶指南

发布时间:2026/9/24 19:09:54

资讯中心
01
ARTICLE

Linux文件夹复制实战:从cp到rsync的进阶指南

Linux文件夹复制实战:从cp到rsync的进阶指南
刚接手一台云服务器打算把网站目录从旧机器往新机器迁几百G的数据我直接敲了条cp -r然后就去喝咖啡了。回来一看复制中断了磁盘提示不够日志里一堆权限报错整个人都麻了。后来我冷静下来改用rsync增量同步加上-a保留权限时间戳再补一个--partial断点续传半个多小时数据就齐了。这个经历让我意识到Linux下复制文件夹看着简单但真要在生产环境里一次性搞对里面的门道比想象中多得多。这篇文章就是围绕“Linux文件夹复制”写的实战总结。不管你是在云主机上迁移网站还是给本地磁盘做备份甚至只是想把项目目录拷给同事大概率都能用上。我尽量不讲废话直接说用法、说参数、说坑最后再给你几个能直接抄的脚本帮助你把复制这件事做得又快又稳。1. 复制前的准备工作先搞清楚你到底要复制什么很多人在复制文件夹之前根本没想清楚需求上来就cp -r等到出了事才回头查。实际上明确需求比敲命令更重要尤其在生产环境一个错误的复制方式可能导致文件不完整、权限错乱甚至把整个服务搞挂。1.1 先想清楚你是要“文件内容”还是“整个目录状态”我见过太多人把“复制文件夹”和“复制文件夹里的所有文件”混为一谈。这两者的差别在隐藏文件、目录结构和元数据上非常大。如果只是想把目录里的文件拷走比如从网上下载的压缩包解压出来的目录里面没有特殊权限和链接那用cp -r就够了。但如果你要复制的是系统配置目录、用户目录、网站运行目录那就必须保留权限、属主、时间戳、软链接甚至ACL。否则复制过去之后服务可能起不来或者文件属主变成了root程序一访问就报错。我自己的习惯是这样的临时拷贝cp -r 源目录 目标目录只关心文件能到。备份迁移rsync -a或者cp -a保留元数据。跨机器传输rsync -azP或者scp -rp还要考虑断点续传和压缩。保留硬链接和xattr需要额外加参数后面会讲。在做任何复制操作之前先花30秒问一下自己目标目录如果缺少权限信息会造成什么后果如果答案是“无所谓”那你尽管用简单的命令如果答案是“肯定不行”那就老老实实加上保留元数据的参数。1.2 理解inode、硬链接和软链接的基本概念很多复制命令的坑都源于对文件系统的底层理解不够。我把最核心的几个概念用大白话讲清楚理解了这些后面各种参数你就很容易记。一个文件在磁盘上其实由两部分组成目录项和inode。目录项记录了文件名和inode编号inode里保存了文件的权限、属主、大小、数据块位置等信息。所谓“硬链接”就是多个目录项指向同一个inode本质上是同一个文件的不同名字。用ls -l看链接数是2的那个文件往往就是有硬链接存在。软链接则是一个独立的文件它的内容只是另一个文件或目录的路径。它有自己的inode所以软链接的权限通常都是lrwxrwxrwx真正有效的是它指向的目标文件的权限。复制文件夹时如果没处理好软链接常见的后果有两种一是把软链接指向的目标文件完整复制了一份导致磁盘多占空间二是软链接复制成了普通文件里面存放的是路径字符串程序一读就报错。cp -r在默认情况下会跟随软链接复制目标内容cp -a则会保留软链接。rsync -a同样默认保留软链接。所以如果你要复制一个含有大量软链接的目录千万别用裸的cp -r否则复制出来的目录结构会变得非常奇怪。2. 最常用的cp命令从新手的依赖到老手的进阶cp命令是所有Linux用户第一个接触的复制工具。但它的参数非常丰富很多人只用了其中一小部分。这一节我们把它讲透。2.1 cp命令基础用法与关键参数cp的基本语法是cp [选项] 源文件 目标 cp [选项] 源目录/ 目标目录当目标是目录时源文件会被复制到该目录下保留原文件名。当目标是文件时源内容会覆盖目标文件。这个覆盖行为是静默的所以我在复制重要文件前经常会在目标端先看一眼避免误覆盖。常用参数可以整理成一张表方便对照参数作用典型使用场景-r递归复制目录最基础拷贝整个目录树-a归档模式等价于-dpR备份、迁移时保留权限和时间戳-p保留权限、属主和时间戳复制可执行脚本或配置文件-d保留软链接不跟随复制含大量symlink的目录-u只在源文件比目标文件新时才覆盖增量同步的初级版-n不覆盖已有文件合并目录时防止误覆盖-v显示执行过程调试时观察--preserveall保留包括xattr、ACL在内的所有属性需要保留扩展属性时我最常用的是cp -a它在很多场合都能代替cp -r而且不用额外操心权限。有个容易混淆的点cp -a已经隐含了-r所以递归复制目录时不用再写-r。另外cp -a在Linux上等于cp -dR --preserveall但在不同版本的系统上可能有细微差异跨平台时建议先用info cp确认。2.2 cp与通配符、特殊文件名的处理复制单个文件很简单但生产环境经常遇到带空格、特殊符号的文件名。直接敲cp my file.txt /backup/是不行的shell会把my和file.txt当成两个对象。正确写法是给文件名加引号cp my file.txt /backup/如果你有一批匹配规则的文件比如所有log文件可以这样cp /var/log/app/*.log /tmp/log_backup/不过这里有个经典坑/var/log/app/*.log如果没有任何匹配项shell会把星号原样传给cp导致报错“No such file or directory”。所以在脚本里最好先开启nullglob或者先判断一下是否存在匹配项。还有一种情况是文件名以减号开头比如-config.txt。直接cp -config.txt /backup/会被cp当作参数处理正确做法是加上--分隔符号告诉命令参数结束cp -- -config.txt /backup/2.3 复制时遇到的权限、属主和硬链接问题cp -r之后发现文件全变成了root这是新手常见的困惑。原因很简单cp -r默认会保留源文件的属主和权限但你自己不是root时可能无法保留属主系统会退化成当前用户。解决方法是使用sudo执行cp -a或者用rsync并加上--owner --group参数。硬链接的问题更隐蔽。当你用普通方式复制一个含多个硬链接的目录时结果可能是每个硬链接都成了独立的文件占用的磁盘空间成倍增加。比如一个文件有5个硬链接每个都是10GB你用cp -r复制后这5个文件各自都是10GB总共50GB源目录却只有10GB。这就是很多人复制目录后磁盘爆满的原因之一。如果你需要保留硬链接关系可以用cp -a配合--preservelinks或者用rsync -H。比如rsync -aH 源目录/ 目标目录/就会尽量保留源端的硬链接结构。3. 大型目录与可靠同步rsync是真正的主力如果你的文件夹只有几百MBcp -a基本够用。但一旦数据量上了几个G甚至几十T或者需要在两台机器之间同步rsync才是真正的主力。它支持增量同步、断点续传、压缩传输、保留各种元数据本质上就是为这种场景设计的。3.1 rsync的核心原理和常用参数rsync最大的特点是“只复制差异部分”。它会把源端文件的校验值或文件大小、修改时间与目标端对比只传输发生变化的块。这样重复执行几次同步时速度会非常快。基础用法rsync -av 源目录/ 目标目录/注意这里有个非常容易踩的坑源目录后面有没有斜杠含义完全不一样。rsync -av /data/ /backup/把/data目录里的内容复制到/backup下不会在/backup中多一层data。rsync -av /data /backup/会把/data本身作为子目录复制到/backup下结果变成/backup/data/。如果你在执行脚本时写反了目录层级就会变得很乱。我在脚本里通常统一使用“源目录/ 目标目录/”这种写法防止歧义。常用的组合参数是-avzP含义如下参数作用-a归档模式保留权限、时间戳、软链接等-v显示详细输出-z传输时压缩适合跨网络复制文本类文件-P等价于--partial --progress支持断点续传并显示进度需要指出-z在传输已经压缩过的文件比如图片、视频、zip包时反而会增加CPU开销收益不大。建议只在传输日志、配置等文本文件时开启。3.2 跨服务器复制scp与rsync怎么选跨服务器复制很多人的第一反应是scp。但scp在细节上不如rsync可靠。举个例子scp在传输大文件时如果连接中断就只能从头再来没有断点续传功能。rsync只要加了--partial中断后再次执行就能从断点继续节省大量时间。另外scp默认不会保留源文件的权限、属主和时间戳除非手动加上-p参数。而rsync -a是一揽子保留。所以我自己的经验是单文件、一次性、文件不大用scp无所谓目录、大文件、可能反复同步优先rsync。跨机器使用rsync最简单的办法是用SSH通道rsync -avzP /data/ userremote_host:/backup/它会自动使用SSH加密传输安全性有保障。如果需要指定SSH端口可以这样写rsync -avzP -e ssh -p 2222 /data/ userremote_host:/backup/如果源端和目标端都装了rsync那基本用不着额外配置。但要注意rsync在目标端也需要有可执行权限否则会报rsync: command not found。这在一些精简的云主机镜像上很常见先拿which rsync检查一下。3.3 增量备份场景下的rsync实践做备份最怕的是每次全量拷贝既耗时间又占空间。rsync天然适合增量备份。可以用--delete参数让目标目录严格跟随源目录删除源端已不存在的文件rsync -avP --delete 源目录/ 目标目录/--delete这个参数要慎用因为一旦源目录里某些文件被误删目标目录里的备份也会被同步删除。如果你的目标是“镜像同步”那它很合适如果你要的是“备份历史版本”就不要加--delete而是用时间戳或者快照方案。我还会在备份脚本里结合--link-dest做增量硬链接备份这个参数能把上一次备份的内容通过硬链接方式保留下来实现“看起来像全量备份实际上只占用增量空间”的效果。示例rsync -aP --link-dest/backup/previous/ /data/ /backup/current/执行完成后current目录是完整备份而它和previous中未变化的文件共用inode不重复占用磁盘。下次执行时把previous换成current即可。这个方案在个人NAS和云服务器备份里都非常实用。4. 权限、属主和时间戳复制元数据的完整方案复制文件内容只是基础真正让复制结果“像”源目录的关键是元数据。这里说的元数据不仅包括权限和属主还包括ACL、xattr、SELinux上下文、时间和硬链接结构。很多线上事故都是因为复制后元数据缺失导致的。4.1 使用cp -a和rsync -a的区别cp -a和rsync -a在很多场景下效果相似但实现机制和使用场景不同。cp -a是本地复制不涉及网络速度一般很快但遇到大目录时无法断点续传也没有进度显示。rsync -a既可以本地同步也可以跨网络同步还支持断点续传和增量只是第一次全量同步时速度可能比cp慢一些。在本地复制一个几G的目录我通常还是用cp -a简单直接。但如果目录里有几万个小文件rsync的校验和计算反而可能更慢这时cp -a更合适。反过来如果要复制的目录几十G而且后续可能还要更新那就直接上rsync。要注意的是rsync -a并不等于cp -a --preserveall。rsync -a默认保留权限、时间戳、软链接和属主但不会保留ACL、xattr和硬链接除非你额外指定-A、-X、-H。很多人以为rsync -a是万能的其实这几个“隐藏属性”需要单独加。4.2 保留ACL、xattr和SELinux上下文ACL是权限的扩展允许你对单个用户或用户组单独设置权限。如果你的目录用了setfacl设置过ACL普通复制会把ACL丢掉。rsync要保留ACL需要加-A参数rsync -aA 源目录/ 目标目录/xattr是文件系统层的扩展属性比如com.apple.quarantine、Docker存储驱动的元数据等。要保留它们rsync需要加-X参数rsync -aX 源目录/ 目标目录/SELinux上下文在某些Linux发行版上是安全防护的重要部分。如果只是普通业务目录可能无所谓但如果复制的是/etc、/var等系统目录SELinux上下文错了服务可能启动失败。rsync的-X会在尽力保留xattr的同时也保留安全上下文但更稳妥的做法是复制完后用restorecon重新恢复目标目录的默认SELinux上下文restorecon -Rv /目标目录关于cp命令想要一次保留所有属性可以用cp -a --preserveall。这个参数组合会尝试保留硬链接、ACL、xattr等。但需要注意目标文件系统必须支持这些属性否则会报错。比如把一个含ACL的目录从ext4复制到FAT32或部分云盘的挂载点上就会遇到Operation not supported这类报错不能直接忽略。5. 常见的坑与排查技巧实录复制文件夹看起来简单实际容易踩的坑非常多。我把自己遇到的典型问题整理成了一个小速查表后面再展开讲几个具体的排查过程。现象常见原因初步解决Permission denied对源目录或目标目录没有读/写权限检查用户、属主、挂载选项复制后文件属主变了没用-a或rsync -a用-o -g或者--owner --group进度卡住不动网络问题、大文件校验慢加--partial并观察带宽中文文件名乱码两端字符集不一致先改LANG环境变量再同步复制的软链接变成了普通文件用了跟随软链接的复制方式改用cp -a或rsync -a复制后磁盘空间反而变大没有保留硬链接关系用rsync -H或cp --preservelinks5.1 提示“Permission denied”时怎么办如果你在复制时碰到Permission denied第一件事不是加sudo而是弄清楚是“没有读源文件权限”还是“没有写目标目录权限”。先检查当前用户对源目录的权限ls -ld 源目录 namei -l 源目录namei -l可以列出路径上每一层的权限非常直观。如果确实缺少读权限可以切换用户或用sudo如果只是目标目录没有写权限就把目标目录的属主改成当前用户或者用sudo chown调整。云服务里还有一种情况是挂载的云盘没有以读写方式挂载或者磁盘满了。用df -h和mount检查一下有时候磁盘输出显示100%文件系统已经自动变成只读这时候任何写入都会报错。这种情况不是复制命令的问题而是磁盘容量或挂载状态的问题。5.2 复制大目录时磁盘空间不够怎么办复制前先看下两端磁盘空间这是基本素养。用du查看源目录实际占用用df -h查看目标空间。du -sh 源目录 df -h 目标路径注意du -sh显示的是文件实际占用ls -lh显示的可能是逻辑大小对于稀疏文件或大量小文件两者差距很大。你把一个稀疏文件复制到不支持稀疏文件的文件系统很可能会瞬间写满磁盘。如果目标确实不够有几种思路不是所有文件都重要用rsync --exclude排除不需要的目录。先压缩再传输用tar流式处理可以减小体积但会增加CPU负载。将部分数据迁移到支持文件扩展的存储或清理目标端无用文件。我经常用的一个技巧是先跑一次rsync的干跑模式把即将复制的文件列表和总大小算出来rsync -avn --stats 源目录/ 目标目录/-n不实际传输只显示结果。这样能提前估算出数据量不至于复制到一半才发现磁盘不够。5.3 复制中断后的恢复与续传复制大文件或大目录时网络偶尔会断、SSH会超时甚至电源也能捣乱。如果没有断点续传几千G的数据从第3G又从头跑心态容易崩。rsync的--partial参数就能解决这个问题。它会把已经传输的部分保留下来下次执行时基于已有部分继续传。这意味着复制命令是可以反复执行的每次中断后再执行一次总能离目标更近。我自己在跑长任务时习惯用screen或tmux把命令丢到后台会话里避免SSH断开就中断。比如tmux new -s rsync_backup rsync -avzP /data/ userremote:/backup/然后把tmux分离去做别的事。即使SSH断了任务也会继续跑。这项技巧在运维场景里非常常用。5.4 中文文件名乱码的处理如果两端系统字符集不一样复制出来的中文文件名会变成???或一串乱码。最常见的原因是源端文件名用的是UTF-8目标端的locale不是UTF-8或者目标文件系统不支持Unicode。解决办法很简单在同步前固定一个统一的locale环境比如export LANGen_US.UTF-8 export LC_ALLen_US.UTF-8 rsync -av /data/ /backup/如果已经复制过去了文件已经乱码想修复可以先看convmv命令它可以把文件名的编码转换过来convmv -f gbk -t utf8 --notest -r /backup/不过这种修复操作有风险最好先备份或用--list看预览结果。说到底解决乱码的根本办法是统一文件系统编码而不是事后补救。6. 效率提升与实用脚本分享前面讲的都是命令基础最后分享一些我自己在用的效率技巧和脚本。用好了复制文件夹这件事会变得非常顺手。6.1 用tar流式复制保留权限和进度cp和rsync在跨目录复制时会出现“先复制文件再设置属性”的过程加上要保留大量小文件的权限速度会慢。某些场景下用tar管道直接流式复制反而更快而且能以一条命令打包、传输、解包。本地复制tar cf - 源目录 | tar xf - -C 目标目录/这个命令会把源目录打包成tar流然后直接管道给另一个tar在目标目录解开。它一个好处是可以利用tar的特性保留权限、属主、时间戳、软链接等元数据而且不需要额外磁盘空间。缺点是打断点续传很麻烦适用场景有限。跨机器复制时也可以这么干tar czf - 源目录/ | ssh userremote_host tar xzf - -C /目标目录/这个方式适合一次性同步数据如果怕网络中断建议还是用rsync。6.2 并行复制工具让几十万个小文件不再痛苦复制大量小文件时cp是单线程的瓶颈往往在磁盘IOPS上。你可以用xargs配合find把复制任务拆成多个并行进程find /data -type f -print0 | xargs -0 -P 8 -I {} cp -a {} /backup/但这种方式也要小心cp -a会丢失目录结构所以更适合平铺文件复制不适合整目录树。更优雅的方案是使用rsync配合--infoprogress2它内部也有多线程优化的考虑但不算严格的多线程。如果你要复制整个目录树并且想并行可以用tar配合pigz等并行压缩工具单纯传数据时也能快不少tar cf - /data | pigz -p 4 | ssh userremote_host pigz -dc | tar xf -这里的pigz是并行版gzip利用多核CPU压缩传输文本文件时效果很显著。不过网络带宽才是真正的瓶颈CPU压缩省下的时间有限。6.3 实用脚本一条命令完成“安全复制”我自己把最常用的复制逻辑写成了一个脚本放在~/.bashrc里每次复制前心里都有底。你可以根据需求修改safe_cp() { if [ $# -ne 2 ]; then echo 用法: safe_cp 源目录 目标目录 return 1 fi local src$1 local dst$2 # 如果目标目录不存在先创建保证rsync正常 ssh_machine${dst%%:*} if [[ $dst *:* ]]; then echo 跨机复制使用rsync rsync -aAXvP --delete -e ssh $src $dst else mkdir -p $dst rsync -aAXvP --delete $src $dst fi }之所以默认加了-A -X是因为很多业务目录都带ACL和扩展属性不加的话复制完容易出怪问题。--delete字段你可以根据实际需求删掉避免误删备份。另外一个备份脚本也很实用我可以把它简化成一行定时任务结合systemd timer每天跑一次rsync -aAXvP --delete --exclude.cache --excludetmp /home/user/ /mnt/backup/这样家目录就能每天增量同步到备份盘而且--delete保证删除的文件也会同步清理避免备份目录无限膨胀。这套方案我用了很多年稳定可靠。写在最后复制文件夹这件事命令好背真正的门道在“知道什么时候用哪个命令”。小目录直接cp -a大目录和跨机数据用rsync要保留特殊属性就记得加-A -X -H网络中断就用tmux加--partial续传。把这些经验串起来你基本就能在Linux下把文件夹复制这件事做到游刃有余。我自己吃过不少亏最深的体会是任何复制操作都要先想清楚“如果失败了我怎么恢复”。保留源目录不动先在目标端试跑一遍确认数据量、权限、空间都没问题再执行真正的同步。复制不是目的数据安全和完整才是。希望这篇指南能帮你少走弯路下次迁移数据的时候能安心地去喝一杯咖啡。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。