☰
SFTP命令行实战:从登录到批量传输的完整指南
2026/10/19 3:05:57 网站建设 项目流程

1. 为什么 SFTP 值得单独拿出来讲

很多人第一次接触 SFTP,是在部署网站或者传文件的时候。图形化工具拖拽几下就完事,看起来没什么门槛。但真正到了服务器只开放命令行、或者需要写自动化脚本批量同步文件的场景,图形界面那套就不够用了。这时候能不能熟练敲 SFTP 命令,直接决定了你是花十分钟搞定,还是折腾一下午。

SFTP 全称是 SSH File Transfer Protocol,注意它和 FTP 完全是两码事。FTP 是独立的一套协议,明文传输,端口 21;而 SFTP 是跑在 SSH 通道里的子系统,默认走 22 端口,所有数据包括账号密码、传输内容全程加密。你可以把它理解成:SSH 给你开了一条加密隧道,SFTP 就是在这条隧道里专门负责搬文件的那位搬运工。也正因为如此,只要你能 SSH 登录一台机器,基本就能用 SFTP,不需要额外开端口、装服务。

这篇文章我打算把 SFTP 从登录到日常命令行的用法完整捋一遍。适合三类人看:一是刚接触 Linux 服务器、还在用图形工具传文件的新手;二是需要写部署脚本、做自动化同步的运维或后端;三是平时用 SFTP 但只会put和get、想系统补一下命令的人。我会把每个命令背后的逻辑讲清楚,配上实际能抄的示例,再把我自己踩过的坑和排查思路一并放出来。看完你至少能做到:不查文档就能完成一次完整的远程文件操作,遇到连不上、传不动、权限报错也能自己定位。

2. SFTP 登录方式全拆解

2.1 最基础的密码登录与端口指定

最朴素的登录方式就是一条命令:

sftp username@host

回车之后会提示你输入密码,验证通过就进入sftp>交互提示符。这里有个细节很多人不知道:SFTP 的密码输入是没有任何回显的,你敲键盘屏幕上不会出现星号或者圆点,这是正常现象,别以为键盘坏了。

如果目标服务器的 SSH 端口不是默认的 22,比如改成了 2222,那就要用-P参数指定端口。注意这里是大写 P,小写 p 在 SFTP 里是preserve(保留文件属性)的意思,两者完全不同,这是新手最容易搞混的地方之一。

sftp -P 2222 username@host

我个人的习惯是,只要端口不是 22,就一定显式写-P,哪怕记错了默认值也不会连错地方。另外主机地址既可以是 IP,也可以是域名,SFTP 本身不关心你用哪种,解析交给系统。

2.2 密钥登录:免密码的正确姿势

生产环境里几乎不会用密码登录,一是弱密码风险高,二是自动化脚本没法交互式输密码。这时候就要用密钥对。前提是你本地已经生成了密钥,并且公钥已经放到了服务器的授权文件里。

sftp -i ~/.ssh/id_ed25519 username@host

-i后面跟私钥文件路径。这里有个常见误区:很多人以为指定了-i就不用管权限了,实际上私钥文件的权限必须是 600,也就是只有属主可读写。如果权限是 644 或者更宽松,SSH 会直接拒绝使用这个密钥,报错大概是 "Permissions are too open"。修复很简单:

chmod 600 ~/.ssh/id_ed25519

我踩过一次坑:把私钥从一台机器拷贝到另一台,scp之后权限变成了 644,怎么都登不上,排查了半天才发现是权限问题。所以拿到新私钥的第一件事,先chmod 600。

2.3 用配置文件简化重复登录

如果你经常连同一批服务器,每次都敲一长串username@host -P 端口 -i 密钥太累了。可以在~/.ssh/config里预先定义好别名:

Host myserver HostName 192.0.2.10 User deploy Port 2222 IdentityFile ~/.ssh/id_ed25519

配置好之后,登录只需要:

sftp myserver

SFTP 会自动读取 SSH 的配置文件,把主机名、用户、端口、密钥全部套用上。这个技巧在管理多台机器时特别省事,而且scp、ssh命令也共用同一份配置,一处定义处处生效。我建议只要你有超过两台常用服务器,就立刻把 config 建起来。

2.4 登录时的几个实用参数

除了上面几个,还有几个参数值得记住。-v是 verbose 模式,会打印详细的连接过程,排查连不上的问题时非常有用,能看到卡在认证的哪一步。-b可以指定一个批处理文件,让 SFTP 非交互式执行一串命令,这个在脚本里会用到,后面实操部分会展开。-r是递归传输,传整个目录的时候必须加,否则只会传目录本身不传里面的内容。

提示:登录失败时先别急着改配置,加上-v看输出,90% 的问题(端口错、密钥权限、用户名错)都能从日志里直接看出来。

3. 命令行核心操作逐条讲透

3.1 目录导航:pwd、ls、cd 的本地与远程之分

SFTP 交互模式里最让人困惑的一点是:命令分本地和远程两套。ls列的是远程目录,lls列的才是本地目录;cd切的是远程目录,lcd切的是本地目录。这个 "l" 前缀就是 local 的意思,记住这个规律,所有本地命令都好记了。

pwd # 查看当前远程目录 lpwd # 查看当前本地目录 ls # 列出远程目录内容 lls # 列出本地目录内容 cd /var/www # 切换到远程 /var/www lcd ~/downloads # 切换到本地下载目录

刚进 SFTP 的时候,远程目录默认是你的家目录,本地目录默认是你执行 sftp 命令时所在的目录。我见过不少人传文件传错地方,就是因为没注意当前本地目录在哪,结果文件传到了意料之外的位置。养成习惯:进 SFTP 先pwd和lpwd各敲一次,确认两边位置。

3.2 文件传输:put 与 get 的完整用法

上传用put,下载用get,这是最核心的两个命令。

put localfile.txt # 上传单个文件到远程当前目录 put localfile.txt /remote/path/newname.txt # 上传并重命名 get remotefile.txt # 下载到本地当前目录 get /remote/path/file.txt ~/local/ # 下载到指定本地目录

传目录要加-r:

put -r myfolder # 递归上传整个目录 get -r remotefolder # 递归下载整个目录

这里有个非常关键的坑:put -r上传目录时,如果远程已经存在同名目录,行为在不同版本上不一致,有的会合并,有的会报错。稳妥的做法是先确认远程目录状态,或者干脆传之前先删掉旧的。另外递归传输大量小文件时速度会很慢,因为每个文件都要单独走一次协议交互,这种情况建议先在本地打包成 tar,传完再在远程解压,效率能提升好几倍。

还有一个-p参数容易被忽略,它能保留文件的修改时间、访问时间和权限模式:

put -p localfile.txt

做增量同步或者需要保持时间戳一致的场景,这个参数很重要。默认情况下上传的文件时间会变成上传那一刻,如果你靠时间戳判断文件新旧,不加-p就会乱套。

3.3 文件管理:mkdir、rm、mv、rename 的边界

远程端的文件管理命令和 Linux shell 很像,但有几个细节要注意。

mkdir newdir # 创建远程目录 rm file.txt # 删除远程文件 rmdir emptydir # 删除空目录 mv old.txt new.txt # 重命名(部分版本支持) rename old.txt new.txt # 重命名(更通用的写法)

rm在 SFTP 里默认只能删文件,删目录要用rmdir,而且只能删空目录。想删非空目录,得先递归删里面的内容,或者退出 SFTP 用ssh执行rm -rf。这是 SFTP 的一个设计限制,它故意不提供递归删除,防止误操作把整个目录干掉。我个人觉得这个限制是好事,至少逼你多想一秒。

mv和rename在不同实现里支持程度不一样,OpenSSH 自带的 sftp 两个都支持,但有些精简版客户端只认rename。写脚本的时候用rename兼容性更好。

3.4 权限与属性:chmod、chown、stat

传完文件经常要改权限,SFTP 里可以直接操作:

chmod 644 file.txt # 修改远程文件权限 chmod 755 script.sh chown user file.txt # 修改属主(需要权限) stat file.txt # 查看文件详细属性

chmod的用法和 Linux 一致,支持数字模式和符号模式。stat会输出文件的大小、权限、修改时间等信息,排查问题时很有用。需要注意的是chown通常需要 root 权限,普通用户改属主会报 "Operation not permitted",这不是命令写错了,是权限不够。

注意:改权限前先想清楚。给脚本 777 看似省事,实际上把执行权限开放给了所有人,生产环境里这是安全隐患。脚本一般 755,普通文件 644,敏感配置 600,按这个来基本不会错。

3.5 查看与执行:cat、less、! 命令的妙用

SFTP 里可以直接看远程文件内容:

cat config.txt # 输出整个文件 less bigfile.log # 分页查看大文件

less在 SFTP 里能用,但交互体验不如在 shell 里流畅,大文件建议还是下载下来看或者用ssh配合tail。

真正好用的是!前缀,它让你在不退出 SFTP 的情况下执行本地 shell 命令:

!ls # 执行本地 ls !pwd # 查看本地当前目录 !tar czf backup.tar.gz myfolder # 本地打包

这个功能在需要临时处理本地文件时特别方便,不用退出再重进。我经常用它来确认本地文件到底在不在,避免传了个不存在的文件还纳闷为什么没反应。

4. 实操过程:从零完成一次完整传输

4.1 场景设定与准备工作

假设现在有个真实需求:把本地一个网站项目目录上传到远程服务器,同时下载服务器上的日志文件回来分析。本地项目在~/projects/mysite,远程目标目录是/var/www/mysite,日志在/var/log/app/下。

第一步先确认本地文件状态:

ls -la ~/projects/mysite du -sh ~/projects/mysite

du -sh看目录总大小,心里有个数,知道要传多久。如果目录里有node_modules这种体积大又不需要传的,先排除掉,不然传半天。

4.2 建立连接并核对两端环境

sftp -P 2222 deploy@192.0.2.10

进去之后先核对环境:

pwd lpwd ls /var/www/

确认远程/var/www/存在,当前远程目录是家目录。如果目标目录不存在,先建:

mkdir /var/www/mysite

这里有个权限问题要提前想:/var/www/通常属于 root,普通用户可能没权限在里面建目录。如果mkdir报 "Permission denied",要么用有权限的账号,要么让管理员提前建好并授权。别硬刚,权限问题硬刚没用。

4.3 执行上传并验证结果

lcd ~/projects/mysite cd /var/www/mysite put -r -p .

lcd切到本地项目目录,cd切到远程目标目录,然后put -r -p .把当前目录内容递归上传并保留属性。用.表示当前目录,比写完整路径简洁。

传完之后验证:

ls -la

对比本地和远程的文件列表,确认数量一致。如果文件多,可以用!ls | wc -l和ls | wc -l分别数一下两边的文件数,数字对得上基本就没漏。

4.4 下载日志并做后续处理

lcd ~/downloads cd /var/log/app get -p app.log

下载完退出:

bye

或者exit、quit都行,效果一样。退出后在本地 shell 里就能直接分析日志了。

整个流程走下来,核心就是"先核对两端位置,再传,传完验证"这三步。我见过太多人跳过验证这一步,结果传了一半断了都不知道,等到线上出问题才发现文件不全。

5. 常见问题与排查技巧实录

5.1 连接类问题速查

现象可能原因排查方法
Connection refused端口错或服务未启动用-v看端口,确认 SSH 服务在跑
Connection timed out网络不通或防火墙拦截ping主机,检查网络策略
Permission denied (publickey)密钥不对或权限过宽chmod 600私钥,确认公钥已授权
Host key verification failed主机指纹变了核对指纹后清理旧记录重连

连接问题里最常见的就是密钥权限。我前面反复强调chmod 600,就是因为这个坑太普遍了。另一个高频问题是主机指纹变化,比如服务器重装过系统,本地还存着旧指纹,就会拒绝连接。这种情况要确认新指纹确实是目标服务器的,再清理旧记录。

5.2 传输类问题与应对

传大文件传到一半断了,是另一个高频场景。SFTP 本身不支持断点续传,断了就得重来。应对办法有两个:一是用支持续传的工具(比如rsync,它底层也走 SSH),二是传之前先压缩,减少传输量。

传输速度慢的话,先判断瓶颈在哪。小文件多导致的慢,打包解决;大文件慢,可能是带宽限制,可以试试加压缩参数。SFTP 协议本身支持压缩,但不是所有客户端都默认开启。

权限报错 "Permission denied" 出现在put时,说明你对目标目录没有写权限。用ls -ld看目录权限,确认自己的用户和组,再决定是换目录还是找管理员授权。

5.3 我踩过的几个真实坑

第一个坑:用put -r传目录,远程已存在同名目录,结果文件被塞进了子目录里,结构全乱了。后来我养成了习惯,传目录前先确认远程目录不存在,或者先删干净再传。

第二个坑:脚本里用 SFTP 批量传文件,没加-b批处理模式,结果卡在交互提示符上,脚本一直挂着。非交互场景一定要用-b指定命令文件,或者用-oBatchMode=yes禁止任何交互提示。

第三个坑:文件名里有空格或特殊字符,直接put my file.txt会被拆成两个参数。正确做法是用引号包起来:put "my file.txt"。这个坑在 Windows 传过来的文件里特别常见。

第四个坑:以为 SFTP 能像scp一样一条命令搞定,结果发现它默认是交互式的。想一条命令传完就退出,得配合-b或者用scp。两者定位不同,SFTP 适合交互式操作和批量命令,scp适合单次快速传输。

5.4 批处理模式:脚本自动化的关键

前面提到-b,这里展开说一下。建一个命令文件sftp_commands.txt:

cd /var/www/mysite lcd ~/projects/mysite put -r -p . bye

然后执行:

sftp -b sftp_commands.txt -P 2222 deploy@192.0.2.10

这样整个传输过程无需人工干预,适合放进部署脚本或定时任务。注意批处理模式下,任何需要交互的命令(比如输密码)都会导致失败,所以必须用密钥登录。另外批处理模式下遇到错误默认会继续执行后续命令,想让它出错就停,可以在命令前加-或者用-oBatchMode=yes配合错误检查。

提示:写批处理脚本时,命令文件里每一行末尾不要有多余空格,某些版本会把它当成路径的一部分,导致莫名其妙的失败。

6. 几个提升效率的进阶习惯

用熟基础命令之后,有几个习惯能明显提升效率。第一个是善用 Tab 补全,SFTP 交互模式支持路径补全,敲一半按 Tab 能省不少事,也能避免手敲路径出错。第二个是把常用操作写成批处理文件存起来,比如"上传网站"、"下载日志"各一个,需要时直接调用。

第三个习惯是传输前先算大小。用du -sh看本地目录,用df -h看远程磁盘剩余空间,确认空间够再传。我遇到过传了一半磁盘满了的情况,前面的文件传上去了,后面的全失败,清理起来很麻烦。

第四个习惯是重要传输做校验。传完之后用md5sum或sha256sum对比两端的文件哈希,确认内容完全一致。对于配置文件、脚本这类不能出错的文件,这一步值得花时间。命令很简单,本地算一次,远程用!前缀或者ssh算一次,对比结果就行。

最后说个心态上的体会:SFTP 命令不多,真正需要记的就那么十几个,但每个都有细节。与其贪多,不如把这十几个练到不用想就能敲出来,遇到问题知道往哪个方向排查。工具的价值不在于功能多,而在于你能不能在需要的时候稳定地用出来。我自己到现在,每次连新服务器还是会先pwd和lpwd确认位置,这个习惯帮我省了无数次传错地方的麻烦。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询