1. 为什么 MacBook 用户总在折腾传输文件这件事
先说个我自己的场景:笔记本上是 macOS,服务器是各种 Linux 发行版(Ubuntu、CentOS、Debian 都碰过),日常要传代码、拉日志、备份数据库、丢配置文件。最早用 Mac 那会儿,我还停留在“用网盘转一道手”的思维里——把文件传到某网盘,再到服务器上另一台能联网的机器下载,绕一大圈,慢且容易出幺蛾子。后来发现,macOS 自带的终端工具链其实完全可以覆盖绝大多数上传和下载场景,只是很多人不知道选哪个、怎么用才稳。
这篇博文就用实际操作为主,把我在 MacBook 上往服务器传文件、从服务器拉文件的几种常用方案完整捋一遍。核心覆盖四类:基于 SSH 的 scp、基于 SSH 的 rsync、交互式 sftp,以及图形化工具兜底。如果你和我一样,平时主要做开发、运维或服务器相关的事儿,这篇文章能帮你少踩一些坑。哪怕你只是偶尔往云服务器传一个安装包,照着步骤来也足够用。
先提醒一句:不管是哪种方案,前提都是你已经有服务器 IP、账号、密码或密钥,而且服务器的 SSH 服务(默认端口 22)是通的。底子没打好,后面所有操作都白搭。
2. 方案选型:先搞明白该用哪种传输方式
2.1 scp、rsync、sftp 到底有什么区别
很多第一次接触这块的朋友容易犯迷糊:同样是传文件,为什么一会儿有人推荐 scp,一会儿有人推荐 rsync,还有人天天用 sftp?其实它们背后都是走 SSH 通道,但定位不同。
- scp(Secure Copy):最直接的文件复制工具,适合一次性、小批量的上传或下载。命令短,语法简单,够用。
- rsync:同步工具,擅长增量传输。比如你本地有一个目录,服务器上也有一个目录,只想把“新增和改动过的文件”传过去,rsync 是首选。对大目录、重复传输、断点续传场景非常友好。
- sftp(SSH File Transfer Protocol):交互式文件传输,登陆之后像 FTP 一样敲命令,支持浏览远端目录、逐文件下载。适合想要“一边看服务器上有什么、一边拉取”的场景,在 Mac 的终端里直接敲 sftp 就能进。
至于图形化工具,比如 Transmit、Cyberduck,还有通过 Finder 的“连接服务器”直接挂载,本质上也大多走 SFTP 协议,只是把命令变成了界面操作。
2.2 为什么优先推荐“命令行优先”而不是一上来就用图形工具
我在实际使用中体会最深的一点:当你需要重复执行、写脚本、做定时任务时,命令行工具的价值是图形工具完全没法比的。举个例子,我每天凌晨要从几台服务器拉取业务日志回本地做分析,用 rsync 一行命令配合 cron 就能定时跑,而如果用图形界面,这意味着我得每天手动打开软件点一遍。
另外,命令行工具天然跨平台。今天你在 MacBook 上会用了,明天换到 Windows 的 PowerShell(配合 OpenSSH)依然有对应命令,学习成本几乎为零。对从事开发、运维工作的人来说,这是必会技能。
2.3 图形化工具存在的意义
当然,不能一棒子打死图形化工具。遇到机器上没终端、需要可视化浏览目录、或者身边同事是不太熟悉命令行的普通用户,客户端工具反而更高效。这部分我会在第 4 节专门展开,给你一套可以“无脑操作”的方案。
3. 核心实操:scp 命令的完整使用指南
3.1 先从最简单的开始:单个文件上传
scp 的基本语法是这样:
scp [选项] 源路径 目标路径把本地 /Users/你的用户名/Desktop/test.zip 上传到服务器 /root/ 目录,命令是:
scp /Users/你的用户名/Desktop/test.zip root@你的服务器IP:/root/回车之后会让你输入服务器密码(如果你配置了密钥登录,这步会跳过)。传输过程会出现进度条,类似这样:
test.zip 100% 12MB 12.0MB/s 00:01看到 100% 就说明传完了。
这里有几个细节值得注意:
- 路径中有空格时,要用引号包住,例如
scp "/Users/你的用户名/Desktop/my file.zip" root@你的服务器IP:/root/ - 默认端口不是 22 时,需要加
-P参数(注意是大写 P,scp 和 ssh 的端口参数大小写不一样,ssh 是小写 p,别记混了) - 如果本地当前目录就是文件所在目录,可以省略绝对路径,直接用
./文件名代替
3.2 下载文件到本地
下载反过来写:
scp root@你的服务器IP:/root/log.tar.gz /Users/你的用户名/Downloads/意思是从服务器的 /root/log.tar.gz 拉到本地下载目录。同样会显示进度条和速度。
3.3 上传和下载整个目录
如果是单个文件,scp 够用了。但如果遇到目录,就得加-r参数(recursive,递归复制):
scp -r /Users/你的用户名/代码工程 root@你的服务器IP:/data/这个命令会把本地的“代码工程”整个目录复制到服务器的 /data/ 下。
下载目录同理:
scp -r root@你的服务器IP:/etc/nginx/ /Users/你的用户名/Desktop/nginx_bak/执行完之后,本地桌面会多出一个 nginx_bak 文件夹,里面是 /etc/nginx/ 的全部内容。
3.4 为什么我后来很少用 scp 传大会话:几个让人头疼的场景
scp 简单归简单,我实际用着用着就发现它的局限:
- 传输大目录、重复传输时每次都全量拷贝,不做增量比较,效率低。
- 中断之后没有断点续传机制,只能从头再来。传一个大文件传到 90% 断了,真的想砸键盘。
- 想要排除某些文件类型(比如 .git 目录、.DS_Store 文件),scp 没有直接的排除参数,你得先压缩再传,或者手动清理。
- 需要保持文件属性(权限、时间戳、owner)时,scp 的支持比较有限。
所以,当文件量变大、传输变得频繁时,我就把主力切到了 rsync。接下来详细聊。
4. rsync:增量同步才是服务器传输的正确打开方式
4.1 rsync 的核心逻辑
rsync 的全称是 remote sync,设计哲学是“只传输差异部分”。它的原理可以这样理解:在传输前会先对比源端和目标端的文件列表,只有新增的、大小变化的、修改时间变化的文件才会被传输,完全没变的文件直接跳过。
这带来的直接好处是:第二次同步同一批文件时,速度极快。比如一个 1GB 的目录,第一次全量传输可能要两分钟,第二次因为文件没变化,瞬间就完成了。
在 macOS 上使用 rsync 有个要注意的老问题:系统自带的 rsync 版本可能比较旧(macOS 自带的通常是 2.6.x,而 Linux 发行版自带的多为 3.x)。新旧版本在传输格式、参数上有些细微差别,好在最常用的参数基本兼容。如果你经常和 Linux 服务器打交道,建议用 Homebrew 装一个新版 rsync:
brew install rsync装完后可以通过rsync --version查看版本确认。
4.2 使用 rsync 上传文件/目录
上传目录的常用命令:
rsync -avz --progress /Users/你的用户名/本地目录/ root@你的服务器IP:/远端目录/其中参数拆开来看:
-a(archive,归档模式):等于-rlptgoD的组合,大致意思就是带上权限、属主、时间戳、符号链接等属性一起同步-v(verbose):显示详细信息,列出每个同步的文件名-z(compress):传输时压缩,节省带宽--progress:显示进度条
命令执行后,你会看到类似:
sending incremental file list file1.conf file2.txt sent 2,344 bytes received 48 bytes 4,784.00 bytes/sec total size is 12,345 speedup is 5.26这里“sending incremental file list”说明走的是增量逻辑,只列出了这次实际有变化的文件。
4.3 断点续传怎么实现
这才是 rsync 真正的杀手锏。传大文件(比如好几个 GB 的数据库备份)传到一半 SSH 断了,在 scp 场景下只能重新来过。但 rsync 加一个参数:
rsync -avz --progress --partial /Users/你的用户名/本地文件 root@你的服务器IP:/远端目录/--partial的含义是保留部分传输的文件,下次执行时基于已有进度继续传输。实测下来,传一个 5GB 的文件,第一次传了 3GB 断网,恢复后再跑同样的命令,只需要传剩下的 2GB。省时省心太多。
4.4 排除不需要同步的内容
在开发场景中,本地目录往往有 node_modules、.git、.DS_Store 这类不需要同步到服务器的内容。rsync 提供了--exclude参数,可以多次使用:
rsync -avz --progress --exclude='node_modules' --exclude='.git' --exclude='.DS_Store' /Users/你的用户名/项目/ root@你的服务器IP:/data/项目/注意排除规则里的路径是相对于同步源目录的,不需要写绝对路径。支持通配符,比如--exclude='*.log'可以排除所有扩展名为 .log 的文件。
4.5 下载目录并保留远端结构
从服务器拉取整个目录到本地,语法和上传一致,只要调换源和目标的顺序:
rsync -avz --progress root@你的服务器IP:/var/log/ /Users/你的用户名/Desktop/服务器日志/这个命令会把服务器上 /var/log/ 里的所有内容拉到本地的“服务器日志”目录。如果本地目录不存在,rsync 会自动创建。
4.6 容易踩坑的地方:目录末尾的斜杠
rsync 有一个非常多见、连老手偶尔都会翻车的点:源目录后面加不加斜杠,含义完全不同。
rsync -avz /本地目录 root@服务器:/远端/:会把“本地目录”这个文件夹本身复制到远端rsync -avz /本地目录/ root@服务器:/远端/:会把“本地目录”里面的内容复制到远端
区别就是:加斜杠表示“目录内所有内容”,不加斜杠表示“目录本身”。
我第一次用 rsync 时,想把本地项目同步到服务器,命令写成了不加斜杠的形式,结果在服务器上生成了 /远端/项目名/ 这样的嵌套目录,后续部署脚本全乱了。从那以后,我每次写 rsync,都会在心里默念一遍“斜杠决定层级”,并且执行前用--dry-run(简写-n)先演练一遍。
4.7 推荐一个保险习惯:先演练,再真传
rsync 的--dry-run参数可以在不实际传文件的情况下,预览将要执行的操作。这个习惯可以帮你避开很多低级错误:
rsync -avz --dry-run /Users/你的用户名/项目/ root@你的服务器IP:/data/项目/执行后只输出“如果真要同步,会传哪些文件”,不会产生实际的写入。确认无误后,去掉--dry-run再真正执行。我基本养成了“每次写新 rsync 命令都先 dry-run 一遍”的习惯,尤其是涉及删除操作时(搭配--delete参数时,更是必须演练)。
4.8 关于 --delete 参数的一个谨慎建议
如果你希望让远端目录和本地目录保持完全一致,本地删掉的文件远端也删掉,可以加--delete:
rsync -avz --delete /Users/你的用户名/项目/ root@你的服务器IP:/data/项目/这个参数我一般建议新手慎用。因为一旦源端路径写错,远端路径的正确文件很可能被一并删掉。如果你要用--delete,请务必备份远端重要数据,并且先用--dry-run确认删除的文件列表中没有“意外内容”。
5. sftp:交互式操作,适合实时浏览远端目录
5.1 一个命令直接进入 sftp 环境
Mac 终端里输入:
sftp root@你的服务器IP输入密码后进入 sftp 的交互式界面,提示符变成sftp>。在这个环境里,你可以用命令浏览远端目录,上传下载文件。
5.2 sftp 常用命令速查
我还真做过一个速查表,贴在这里:
| 命令 | 作用 | 使用示例 |
|---|---|---|
pwd | 查看远端当前目录 | pwd |
lpwd | 查看本地当前目录 | lpwd |
ls | 列出远端目录内容 | ls -l |
lls | 列出本地目录内容 | lls |
cd | 切换远端目录 | cd /var/log |
lcd | 切换本地目录 | lcd Desktop |
put | 上传文件到远端 | put 本地文件.txt |
mput | 上传多个文件 | mput *.txt |
get | 下载远端文件到本地 | get 远端文件.txt |
mget | 下载多个文件 | mget *.log |
exit/quit | 退出 sftp | exit |
5.3 实际场景演示:拉取服务器日志
假设我要查看服务器 /var/log/nginx/ 下有哪些日志文件,并下载最近几天的访问日志。
进入 sftp 后:
sftp> cd /var/log/nginx sftp> ls -l -rw-r----- 1 www-data www-data 12345 Dec 10 10:00 access.log -rw-r----- 1 www-data www-data 23456 Dec 10 09:00 error.log然后切换本地目录,再下载:
sftp> lcd /Users/你的用户名/Desktop/日志备份 sftp> get access.log Fetching /var/log/nginx/access.log to access.log /var/log/nginx/access.log 100% 12KB 12.0KB/s 00:01如果你想下载错误日志,并且想保留远端文件名,直接:
sftp> get error.log如果全部日志都要,可以这样:
sftp> mget *.log5.4 sftp 的局限
sftp 适合临时性查看、小批量操作。但如果涉及大量文件、需要增量同步的场景,sftp 就没有优势了。每次 get/put 都是单文件传输,没有增量比较逻辑。所以我在实际使用中的分工是:
- 临时看个目录、传一两份配置,用 sftp
- 批量发布代码、服务器间同步、做备份,用 rsync
- 一句话就能搞定的单次文件复制,用 scp
6. 图形化工具:不想敲命令时的兜底方案
6.1 利用 macOS Finder 自带的“连接服务器”功能
说实话,很多人不知道 macOS 的 Finder 其实自带 SFTP 挂载功能,不需要装额外软件。
操作步骤:
- 打开 Finder,按快捷键
Command + K - 在弹出的窗口中输入
sftp://你的服务器IP - 点击“连接”
- 输入用户名和密码
连接成功后,服务器根目录就像本地磁盘一样显示在 Finder 侧边栏,可以直接拖拽上传或下载文件。这种方式适合小文件、不频繁的场景,胜在零安装、零学习成本。
不过它的限制也很明显:传输速度不够稳定,传输大文件时 Finder 偶尔会转菊花,而且不支持断点续传和增量同步。
6.2 第三方客户端:Cyberduck 与 Transmit
如果你的工作流是高频和服务器交互、又不想完全依赖命令行,可以试试第三方 SFTP 客户端。
Cyberduck 是免费的,支持 SFTP、FTP、WebDAV,跨平台,macOS 上用得很顺手。下载安装后,新建连接,选择 SFTP(SSH File Transfer Protocol),填上服务器 IP、端口、用户名、密码,双击即可连接。Cyberduck 还支持把远端目录保存为“书签”,下次直接点开,体验和本地文件管理器很像。
Transmit 是收费软件,但功能更强大。它的特点包括:
- 支持同时连接多个服务器,可在面板之间直接拖拽传输
- 支持 Transmit Disk,可以把远程目录挂载到 Finder 中当作本地磁盘
- 支持批量操作、队列传输
- 与 macOS 系统集成度高,右键菜单直接上传
价格不算便宜,但如果你每天都要和服务器文件打交道,可能一天省下的时间就值回票价了。
6.3 图形化工具什么时候该用、什么时候该回到命令行
我得说句实话:图形化工具虽好,但很多自动化场景它替代不了。比如你要每天凌晨 2 点自动从服务器拉取备份到本地,图形化工具很难做到。这时候 rsync + cron 才是正解。
我的使用习惯是:
- 传几个配置文件、改改远端目录内容,用 Finder 挂载或 Cyberduck
- 需要定时同步、增量备份、大批量部署,命令行(rsync)
- 服务器上目录结构不熟悉,想黑盒探索一下,用 sftp 或图形化工具
一句话总结:图形化工具适合“看得见、摸得着”的人机交互,命令行工具适合“自动化、脚本化”的机器交互。两个都不冲突,按需切换。
7. 常见问题与排查技巧实录
7.1 连接超时或 Permission denied
这类问题排第一位的频率非常高。
排查思路:
- 确认服务器 IP 有没有写错,端口通不通:本地终端执行
nc -vz 服务器IP 22,如果显示 connected 说明端口通 - 确认 SSH 服务有没有启动:在服务器上执行
systemctl status sshd或service ssh status - 确认用户名和密码是否正确,注意 Linux 用户密码默认不回显,别以为键盘坏了
- 如果服务器只允许密钥登录,那你需要把本地公钥加到服务器的
~/.ssh/authorized_keys里
检查完还不行,就看服务器的/var/log/auth.log(Debian/Ubuntu)或/var/log/secure(CentOS),里面会有详细的拒绝原因。
7.2 传大文件速度慢、容易断
没有万能的加速方案,但有几个办法叠加起来效果明显:
- 优先用 rsync 加
--partial,断点续传 - 加
-z参数让传输时压缩,文本类文件(代码、日志、JSON)压缩效果非常显著 - 如果文件数量巨大(比如几万个零碎小文件),建议先在本地打包成一个 tar 压缩包再传,传输速度会快好几倍
- 服务器上 CPU 允许的话,用
-e "ssh -C"强制 SSH 压缩
实际测试过:一个包含 5 万个中小文件的目录,rsync 直接同步耗时可能几十分钟还容易中断;先打包成 tar.gz(文件总数变成 1),再传输,全过程 5 分钟搞定。打包思路在传输大量小文件时永远有效。
7.3 中文文件名乱码
macOS 的文件系统(APFS/HFS+)对中文文件名的编码方式和 Linux 服务器可能会有不一致,导致传过去之后文件名乱码或者无法访问。
这问题没有完美的代码级解释,但可以从根源上规避:在打包文件时先用英文命名规范整理一遍,或者在 tar 打包时指定编码格式。如果是少数几个文件,直接重命名再传是最省事的方案。如果你必须保留中文文件名,实测下来 macOS 的 sftp 和 rsync 对 UTF-8 的支持效果相对好一些,scp 偶尔会有问题。
7.4 scp 命令不存在
某些精简过的服务器系统可能默认没装 scp。这时候有两个选择:
- 服务器上安装 openssh-clients(CentOS)或 openssh-client(Debian/Ubuntu)
- 改用 rsync,如果服务器连 rsync 也没有,需要安装 rsync
scp: command not found还可能出现在本地 macOS 上。这种情况很少见,但如果出现,排查/usr/bin/scp是否存在,必要时通过xcode-select --install安装命令行开发者工具。
7.5 权限问题:Permission denied 却确定密码是正确的
这种情况常见于 root 用户默认禁止 SSH 登录的服务器。很多云主机默认禁止 root 直接远程登录,你需要先用普通用户登录,再切换到 root。
另外还要注意目录权限。假如你要上传到 /var/www/ 这个目录,当前用户没有写权限,也会报 Permission denied。解决办法:先把文件传到 /tmp/ 或家目录,登录服务器后移到目标目录;或者调整目标目录属主/权限。
7.6 防火墙和安全组问题
使用云服务器时还有一个高频坑:SSH 端口被安全组挡住了。云服务商的安全组规则和服务器本地的 ufw/firewalld 都要同时放行 22 端口(或自定义的 SSH 端口)。
如果你改了 SSH 端口(比如改用 2222),那么传输命令中必须显式指定端口。scp 是-P 2222,rsync 是-e "ssh -p 2222":
rsync -avz -e "ssh -p 2222" /本地目录/ root@服务器IP:/远端目录/7.7 断点续传只对 rsync 有效,别指望 scp
这里再强调一遍,因为我真的见过很多同事搞混。scp 和 sftp 都没有断点续传能力,传大文件时一旦断开,只能从零开始。rsync 的--partial才能保留已传部分。所以传大文件的黄金法则就一条:别用 scp,用 rsync。
8. 实操总结:搭建一个“一键同步”的日常方案
8.1 具体需求
我的日常需求是:本地某个项目目录要同步到服务器上指定的发布目录,同时从服务器拉取运行日志到本地备份。整个过程希望只输一条命令就完成全部操作。
8.2 操作步骤
先用 Mac 自带的“文本编辑”或 VS Code 创建一个 shell 脚本文件,比如叫sync_server.sh,内容如下:
#!/bin/bash # 配置区 SERVER_IP="你的服务器IP" SERVER_USER="root" REMOTE_DIR="/data/www" LOCAL_DIR="/Users/你的用户名/项目" BACKUP_DIR="/Users/你的用户名/Desktop/服务器日志" echo "开始同步代码..." rsync -avz --delete --exclude='node_modules' --exclude='.git' --exclude='.DS_Store' "$LOCAL_DIR/" "$SERVER_USER@$SERVER_IP:$REMOTE_DIR/" echo "开始拉取日志..." rsync -avz --progress "$SERVER_USER@$SERVER_IP:/var/log/" "$BACKUP_DIR/" echo "全部完成"保存后,在终端里赋予执行权限并运行:
chmod +x sync_server.sh ./sync_server.sh之后每次需要同步,只需要进入脚本目录执行./sync_server.sh。如果你对这个脚本做了密钥登录配置,整个过程连密码都不用输。
8.3 配置 SSH 密钥免密登录
如果你觉得每次输入密码很烦,可以配置 SSH 密钥。在本地执行:
ssh-keygen -t ed25519 -C "你的备注"一路回车即可,生成的公钥在~/.ssh/id_ed25519.pub。然后把公钥内容追加到服务器的~/.ssh/authorized_keys:
cat ~/.ssh/id_ed25519.pub | ssh root@服务器IP "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"之后再传输时就不需要密码了。这个操作建议做一次,长期受益。
9. 我从实际踩坑中总结的几条经验
真正熟练之后,你会发现这些工具本身并不复杂,复杂的是在实际场景中的应变。这里把我反复踩坑换来的经验整理成几个核心要点,供你参考。
第一,传大量零碎小文件前,永远先考虑打包。文件系统对“数量”的敏感度远高于“总大小”,几万个小文件会让传输效率暴跌,还会增加 SSH 中断的概率。而把几万个文件变成一个 tar.gz 包,传输效率能有数量级的提升。
第二,rsync 的 --delete 是一把双刃剑。它在保持两边目录一致的场景下确实好用,但前提是你对源路径有十足把握。我在实际使用中养成了一个铁律:带 --delete 的命令,必须加 --dry-run 先跑一遍,看到实际会删除的文件列表确认无误后,才去掉演练参数执行。
第三,传输工具的选型与文件大小强相关。几个文件、几百 KB 的配置,scp 足够;几十 GB 的数据、需要断点续传,rsync 是唯一稳妥选择;临时浏览远端目录、想看看服务器上有什么,sftp 顺手;不想记命令的人,图形化工具兜底。没有“最强大”的工具,只有“最合适”的方案。
第四,别忽视文件名编码问题。跨系统传文件时,中文文件名是最大的不确定因素。日常使用中我给服务器上的文件命名基本只用英文、数字、下划线,这一条小习惯帮我少处理了非常多编码乱码问题。
最后再分享一个小技巧:可以在 macOS 的 shell 配置里给常用命令设置别名。比如在~/.zshrc中加入:
alias updata='rsync -avz --progress --exclude=".DS_Store" ~/项目目录/ root@服务器IP:/data/www/'这样在终端输入updata就完成了代码发布,简单直接,效率很高。也希望你在折腾的过程中,根据自己使用场景持续调整,找到最适合自己的那套传文件节奏。