scp/rsync 命令速查表 - Linux 远程传输常用命令大全
同样是往服务器传文件,scp 和 rsync 的差异会直接决定网络抖动时你损失多少。scp 每次整体重传:改一个字节也要重发整个文件,中断后没有续传位置只能从头再来,内网无所谓,跨公网传 2GB 就意味着重来两次。rsync 用滚动校验和判断哪些块没变、只传差异;配合 --partial 保留中断处的半成品、--append-verify 增量追加并校验,两者一起能逼近续传效果。另一个关键差别是尾部斜号:rsync src/ 同步目录内容,rsync src 同步目录本身,这决定了目标端会不会多出一层嵌套。四组覆盖 --delete、--exclude 与 --include 的先后顺序、--bwlimit 限速、--dry-run 预演和 -e 传 ssh 参数。选择标准清晰:一次性单文件用 scp,目录同步、增量发布、定时备份一律用 rsync。
典型使用场景
面向每天要在本机和服务器之间搬文件的运维/后端工程师。scp 和 rsync 长得像、都能传文件,但语义完全不同:scp 是「复制」,rsync 是「对齐两端状态」,只有 rsync 会比较大小与时间戳并只传差异。真正的分界线有三个:一次性投递用 scp 更快更省心;需要保留权限与时间戳、需要反复增量同步、需要在断网后接着传,就必须上 rsync;要把本地目录变成远端的精确镜像,rsync 的 -a 配合 --delete 是唯一可靠解——但也正是这里最容易出事。
scp 基础传输 8
scp file user@host:/pathscp user@host:/path/file .scp -r dir user@host:/pathscp -P 2222 file user@host:/pathscp -i ~/.ssh/id_rsa file user@host:/pathscp -C file user@host:/pathscp -q file user@host:/pathscp -v file user@host:/pathrsync 基础同步 8
rsync file user@host:/pathrsync user@host:/path/file .rsync -r dir user@host:/pathrsync -a dir user@host:/pathrsync -av dir user@host:/pathrsync -az dir user@host:/pathrsync -e "ssh -p 2222" file user@host:/pathrsync -e "ssh -i key" file user@host:/pathrsync 增量同步 6
rsync -av --delete src/ user@host:/path/rsync -av --update src/ user@host:/path/rsync -av --ignore-existing src/ user@host:/path/rsync -av --dry-run src/ user@host:/path/rsync -av --progress src/ user@host:/path/rsync -av --partial src/ user@host:/path/rsync 过滤选项 5
rsync -av --include="*.txt" src/ dest/rsync -av --exclude="*.tmp" src/ dest/rsync -av --exclude=".git" --exclude="node_modules" src/ dest/rsync -av --exclude-from=exclude.txt src/ dest/rsync -av --filter="+ *.txt" --filter="- *" src/ dest/rsync 高级选项 6
rsync -av --compress src/ dest/rsync -av --checksum src/ dest/rsync -av --size-only src/ dest/rsync -av --modify-window=1 src/ dest/rsync -av --log-file=rsync.log src/ dest/rsync -av --stats src/ dest/常用场景 Common Patterns 6
rsync -avz --progress --partial file user@host:/pathrsync -avz --delete src/ user@host:/path/rsync -avz --exclude=".git" --exclude="node_modules" src/ dest/rsync -avz --backup --backup-dir=backup src/ dest/rsync -avz --max-size=100m src/ dest/rsync -avz --bwlimit=1000 src/ dest/参数矩阵
| 参数 | 作用 | 示例 |
|---|---|---|
scp -r | 递归复制目录,但不保留权限位与 mtime,落地文件常变成默认属主 | scp -r dir user@host:/path |
scp -P | 指定 SSH 端口,注意是大写 P,与 ssh 命令行的小写 -p 语义不同 | scp -P 2222 file user@host:/path |
rsync -a | 归档模式,保留权限、属主、时间戳、符号链接,目录同步的事实标准 | rsync -a dir user@host:/path |
--delete | 删除目标端源端已不存在的文件,用于精确镜像;配合 --dry-run 先验一遍 | rsync -av --delete src/ user@host:/path/ |
--partial | 保留已传输的部分文件,下次同命令可续传;对大文件中断至关重要 | rsync -avz --progress --partial file user@host:/path |
易错点与避坑指南
现象rsync 传大文件传到 60% 断线,重跑后从 0% 重新开始。
原因未加 --partial,rsync 默认把临时文件删掉,下次无法续传。
处置固定用 rsync -avz --progress --partial 组合,断线后重跑同一条命令即可接着传。
现象rsync -r dir user@host:/path 之后,远端多出一层同名目录(/path/dir/dir/...)。
原因源端 dir 不带尾斜杠时,rsync 会把目录本身作为一个条目复制进目标路径。
处置写成 dir/ 表示「把 dir 的内容同步进 /path」,这是镜像与覆盖场景唯一正确的写法。
现象跑 rsync -av --delete 后,远端目录里一些手工放进去的文件消失了。
原因--delete 会删除目标端源端不存在的任何条目,它不区分「谁放的」。
处置先 rsync -av --delete --dry-run src/ user@host:/path/ 预演,再加 --backup --backup-dir=backup 保留被删内容。
现象scp -r 上传的目录在远端 ls -l 显示权限和时间戳全变了。
原因scp -r 只做递归复制,不传权限位与 mtime。
处置改用 rsync -a,同一条命令即可保留权限、属主与时间戳。
现象rsync 报 Permission denied (publickey) 或连错端口。
原因rsync 的 -p 不是 scp 的 -P,端口和密钥要通过 -e "ssh -p ..." 传给 ssh 本身。
处置写成 rsync -e "ssh -p 2222" 或 rsync -e "ssh -i key" src/ user@host:/path/。
排障路径
1镜像同步前先预演,确认 --delete 会删什么
rsync -av --delete --dry-run src/ user@host:/path/输出里带 deleting 的行就是即将被删的条目,确认无误再去掉 --dry-run。
2大文件中断后续传
rsync -avz --progress --partial file user@host:/path--partial 保留已完成部分,重跑同一条命令即可从断点继续。
3目标端非默认端口 / 指定私钥
rsync -e "ssh -p 2222" file user@host:/path端口与密钥属于 ssh 自身的参数,必须通过 -e 传进去。
4只同步源码,不带依赖与版本库
rsync -avz --exclude=".git" --exclude="node_modules" src/ dest/排除规则可反复追加 --exclude,是控制同步体积最省事的手段。
命令示例
先 dry-run 看清楚,再真同步
rsync -av --dry-run --exclude=".git" --exclude="node_modules" src/ user@host:/srv/app/
rsync -avz --exclude=".git" --exclude="node_modules" src/ user@host:/srv/app/rsync 只传「有差异」的部分,第一次跑必然快、第二次几乎瞬时。关键是永远先 --dry-run:输出里的 deleting / creating 列表就是远端会被改动或删掉的东西,看清了再去掉这个参数。
输出
sending incremental file list file1 file2 sent 1,234 bytes received 56 bytes 2,580.00 bytes/sec total size is 12,345 speedup is 9.52
镜像同步目录并保留被覆盖的旧文件
rsync -avz --delete --backup --backup-dir=backup src/ user@host:/srv/app/--delete 让远端严格镜像本地(远端多出来的文件会被删),--backup --backup-dir=backup 则把被覆盖/被删的那一份挪进远端的 backup/ 子目录。两者一起用是「既能保证一致,又不会真丢东西」的标准姿势。
输出
sent 512 bytes received 96 bytes 1,216.00 bytes/sec total size is 12,345 speedup is 20.30
非 22 端口 + 指定私钥的组合写法
rsync -avz -e "ssh -p 2222" src/ deploy@host:/srv/app/
scp -P 2222 -i ~/.ssh/id_ed25519 dist.zip deploy@host:/tmp/rsync 的端口在 -e "ssh -p 2222" 里(ssh 的参数),scp 的端口是独立的 -P 2222(大写),两处极易写混:rsync 写 -p 会被当成 rsync 自己的参数,scp 写小写 -p 变成「保留时间戳」而静默连错端口。
断点续传大文件并限带宽
rsync -avz --partial --progress --bwlimit=1000 bigfile.iso user@host:/data/--partial 让中断的传输留下部分文件,下次 rsync 接着传而不是从头再来;--bwlimit=1000 把速率压在 1000 KB/s,避免打满一条共享的办公网出口。两者都只影响传输行为,不改变落地文件内容。
大文件上传后先算校验和再删本地
rsync -avz --checksum dist.tar.gz user@host:/srv/releases/
md5sum dist.tar.gz网络传输成功不等于内容正确。用 --checksum 让 rsync 按内容而非时间戳判断差异,再在本地算一次 md5sum 跟远端对照,确认无误才删源文件——这是发布大包时唯一不会事后追悔的顺序。
常见坑与注意事项
- rsync --delete 是按「源目录列表」删除目标端多余文件的:只要源路径写错、末尾少一个斜杠或挂载点没挂上,远端整个目录(含数据库文件、上传的用户文件)会在一次同步里被清空。首次执行务必加 --dry-run 看 deleting 行。
- rsync 源路径末尾的斜杠有决定性含义:`src/` 同步的是目录内容(`dst` 里直接出现内容),`src` 同步的是目录本身(`dst` 里出现 `dst/src/`)。这一个斜杠之差就是「平铺」和「多套一层目录」两种结果。
- scp -r 不保留权限位与 mtime:递归上传后远端文件权限取决于 umask,可执行脚本可能变成不可执行,增量同步时也全部被判为「已改变」而全量重传。需要保留属性请用 rsync -a。
- rsync 不自带 -z 之外的跨网络保护,且不带重试:中断后若不加 --partial,下次会从头重传整个大文件。公网传输建议配 ssh 的 ServerAliveInterval 与 -e "ssh -o ..." 选项。
- 在目标路径上误用 --delete 时,`--exclude` 的模式不会保护被排除的目录本体——被排除的文件在目标端不会被删除,也不会被更新,容易让人误以为同步「成功」但实际是陈旧数据。
- Windows 上用 Git Bash / MSYS 跑 rsync(cwRsync、WSL 路径)容易踩路径转换的坑:`-P 2222` 之类参数可能被当作路径改写,报错信息又指向完全无关的文件。遇到诡异参数错误先用 `--dry-run` + `echo` 确认参数原样送达。
提示
- scp 适合简单文件传输,rsync 适合目录同步和增量传输。
- rsync 的 --delete 会删除目标端多余文件,使用前确认目标端没有重要数据。
- rsync 的 src/ 和 src 不同:src/ 同步目录内容,src 同步目录本身。
- rsync --bwlimit=800 -avz src/ dest/ 用 -z 压缩并在链路上限到 800KB/s,跨公网时能给其它服务留出带宽,也避免触发对端限速策略。
- rsync -a --delete 时先加 --dry-run 或 -n 跑一遍,看清将被删除的远端文件再真正执行,这是唯一能防止 mirror 参数误删的做法。
- scp -3 在本地与远端之间传输时经由本机中转,不依赖两端的 scp 服务都支持 sftp 协议,跨版本时能避开老服务器的 scp 兼容问题。
常见问题
rsync 的 --update 和 --ignore-existing 到底差在哪?
两个都会保护目标端已有的东西,但保护依据完全不同。--update 是拿源端与目标端的修改时间来比:目标端比源端新就跳过,源端更新了才覆盖,所以它只保护「你手工改过并且改得更晚」的文件。--ignore-existing 完全不看时间,只要目标端有这个路径就一律不传,哪怕源端那份更新也不动。选前者适合持续同步开发目录,选后者适合往一台已有大量文件的机器上只做增量投放。
把代码目录同步到服务器时,怎么让版本库和依赖目录不被传过去?
用 --exclude 逐项排除,写成 rsync -avz --exclude=".git" --exclude="node_modules" src/ dest/。两个 --exclude 可以并列,也可以继续追加更多模式;模式串按 rsync 的通配规则匹配,匹配到目录时会连其内容一起跳过,所以 node_modules 不需要再单独写一条子规则。如果排除项多到命令行放不下,就改用 --exclude-from=exclude.txt 把规则写进文件再传路径,避免超长命令行在不同 shell 下的引号问题。
同步完怎么知道到底传了多少、又跳过了多少文件?
加 --stats,它会在末尾打出传输的文件数、实际字节数、匹配到的文件数与耗时,能立刻看出这次是全量重传还是只补了差异。如果统计显示大量文件被反复判定为「有差异」,那说明 rsync 用的快速判断(大小或修改时间)不够准,可以换 --checksum 强制逐文件算校验和来比对,代价是要把两份内容都读一遍。更省事的折中是 --size-only,只比大小、忽略时间戳,适合时间戳经常被其他工具改动的目录。
两端时间戳总是对不上,目录里的文件被反复重传,怎么解决?
先确认是不是文件系统精度的问题。FAT 一类以 2 秒为单位记录 mtime,而 rsync 的默认比较窗口小于这个粒度,于是同一个文件每次都判定为「不同」。这种情况加 --modify-window=1 把容忍窗口放大到 1 秒即可,同步命令写成 rsync -av --modify-window=1 src/ dest/。如果时间戳本身是准的、差异来自别处,就别去调窗口,改用 --checksum 或 --size-only 让比较依据从时间换成内容或体积,从根上绕开时间戳。
include、exclude 和 --filter 规则该怎么搭配才不互相吃掉?
规则是自上而下顺序匹配的,先命中先生效,后面的规则就不再看。所以「只传 txt」的经典写法是给一条 include 放行、紧跟一条 catch-all 拒绝:rsync -av --filter="+ *.txt" --filter="- *" src/ dest/。如果只写 --include="*.txt" 而没有兜底的 - *,其余文件并不会被自动排除,结果往往是整个目录都被同步。如果规则多、想复用一份列表,就用 --exclude-from=exclude.txt;简单的单条排除用 --exclude="*.tmp" 最短。
由 巧匠 维护
公开更新于 2026年7月21日,内容持续校对官方文档。