Skip to content

04|文件传输

本机写好的配置要传到服务器、服务器上的日志要拉回来分析、发布包要推到多台机器——远程传文件是高频操作。场景不同,工具也不同:

工具适用场景特点
scp临时传一两个文件命令还在,但底层协议已换(见下文)
sftp交互式浏览后传文件配合批处理可脚本化
rsync增量同步、大目录、断点续传比对差异后只传变化部分
lrzsz终端里临时拖个小文件依赖终端客户端,ZMODEM

本篇讲这几种工具怎么用、各自适合什么场景,以及传输时容易踩的坑。

一、传文件前的共性确认

传文件之前确认三件事,避免一半以上的低级错误:

bash
# 1. 目标目录是否存在?
ssh user@host 'ls -d /etc/nginx/conf.d'
# 不存在时,scp 会把文件写到 /etc/nginx/conf.d 这个"文件"而非目录内

# 2. 目标用户有写权限?
# Permission denied 在连上后发生,说明文件系统权限不够

# 3. 会不会静默覆盖?
# scp 默认直接覆盖,没有任何提示

二、scp

scp 走 SSH 加密,用法和 cp 类似,只是路径可跨机器。

scp 的协议已经换了

从 OpenSSH 9.0(2022 年)开始,scp 命令底层不再用老的 SCP 协议,改用 SFTP 协议。原因:老 SCP 协议有安全问题(CVE-2020-15778),且很难在不破坏兼容性的前提下修复。

实际影响:

  • scp 命令照常用,写法和以前一样,不用改
  • 底层走的是 SFTP,比老协议安全
  • RHEL 9 等新系统默认就这么跑
  • 老的 SCP 协议还能用 -O 强制启用,但一般没必要

所以"scp 不能用了"是误传——命令还在,只是底层换了更安全的实现。日常临时传文件,scp 仍然是最顺手的。

基本用法

基本用法

bash
# 上传单个文件
scp ./app.conf root@192.168.10.129:/etc/myapp/app.conf

# 下载
scp root@192.168.10.129:/var/log/messages ./messages

# 指定端口和私钥(注意:-P 大写)
scp -P 2222 -i ~/.ssh/id_ed25519_ops ./app.conf root@host:/tmp/

scp -P 是大写;ssh -p 是小写。 scp -p(小写)是保留文件属性,不是指定端口。

常用参数

bash
scp -r ./dist root@host:/opt/myapp/       # 递归目录
scp -p ./backup.tar.gz root@host:/backup/  # 保留时间戳和权限
scp -l 20480 ./bigfile root@host:/data/    # 限速(Kbit/s)
scp -C ./logs.tar root@host:/tmp/          # 启用压缩

-l 20480 约等于 20 Mbit/s。跨机房大文件不加限速可能打满链路影响线上服务。

覆盖风险

scp 覆盖同名文件无任何提示:

bash
# 先备份远端文件
ssh root@host 'cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak'

# 再传新文件
scp ./nginx.conf root@host:/etc/nginx/nginx.conf

三、sftp

sftp 提供交互式文件传输客户端:

bash
sftp root@192.168.10.129

进入后常用命令:

命令作用
pwd / lpwd看远端/本地目录
ls / lls列远端/本地文件
cd / lcd切远端/本地目录
put <file>上传
get <file>下载
bye退出

命令前加 l(local)操作本地,不加操作远端。

批处理模式

bash
cat > sftp-batch.txt <<'EOF'
cd /tmp
put app.tar.gz
put app.conf
bye
EOF

sftp -b sftp-batch.txt root@192.168.10.129

四、rsync

rsync 的核心是增量同步:对比源端和目标端,只传变化的内容

基本用法

bash
# 本地同步到远端
rsync -av ./dist/ root@192.168.10.129:/opt/myapp/dist/

# 远端拉回本地
rsync -avP root@host:/var/log/nginx/ ./nginx-logs/

常用参数

参数作用
-aarchive 模式:递归+保留权限/时间戳/软链接/属主
-v显示传输文件列表
-z传输时压缩(文本类文件有效)
-P--partial --progress:断点续传+进度
--delete让目标端与源端完全一致,删除目标端多出来的文件
--dry-run预演,列出变更但不执行
-e 'ssh -p 2222'指定 ssh 端口和参数

路径斜杠陷阱

rsync 源路径末尾的斜杠极其重要:

bash
# 带斜杠:复制 dist/ 下所有内容到 /opt/app/
rsync -av ./dist/ host:/opt/app/
# → /opt/app/file1, /opt/app/file2

# 不带斜杠:复制 dist 目录本身到 /opt/app/
rsync -av ./dist host:/opt/app/
# → /opt/app/dist/file1, /opt/app/dist/file2

带斜杠=复制内容,不带斜杠=复制目录本身。未确认时先用 --dry-run 预览:

bash
rsync -avP --dry-run ./dist/ root@host:/opt/myapp/dist/

--delete 的危险性

--delete 让目标端与源端完全一致,目标端多出来的文件会被删除:

bash
rsync -avP --delete ./dist/ root@host:/opt/myapp/dist/

源端如果写错了(空目录、挂载失败),目标端的内容会被清空。 --dry-run 的目的不只是确认目录层级,还包括确认源端内容正确。

文件属性保留

rsync -a 尽量保留属性,但属主/属组能否保留取决于执行用户有没有权限:

bash
# 非 root 用户同步过去,属主变成登录用户
rsync -av ./ scripts/ user@host:/opt/scripts/

# 显式设置目标端权限(Web 静态文件发布场景)
rsync -av --chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r ./dist/ host:/opt/app/

五、传输校验

关键文件传输后做校验,确认没有损坏。TCP 校验和较弱,应用层 SHA-256 是对抗静默数据损坏的简单手段:

bash
# 源端生成哈希
sha256sum app.tar.gz > app.tar.gz.sha256

# 传输
scp app.tar.gz app.tar.gz.sha256 root@host:/tmp/

# 远端校验
ssh root@host 'cd /tmp && sha256sum -c app.tar.gz.sha256'
# 期望:app.tar.gz: OK

# 或下载后将本地生成的哈希与远端源文件对比
ssh root@host 'sha256sum /backup/db_export.sql' | diff - <(sha256sum ./db_export.sql)

发布包、备份包、离线安装包,都要加传输校验。

六、堡垒机文件传输

有堡垒机后,文件传输方式取决于授权策略。

如果堡垒机只允许 Web 文件管理,自己再开 SCP 直连目标机器等于绕过审计。

方式说明
Web SFTP浏览器中上传/下载,走审计
客户端 SFTP通过堡垒机代理连接
审批+分发先工单审批,由堡垒机分发到目标

JumpServer 里的授权规则要看两个设置:是否允许文件传输(部分授权只给"连接"),下载是否有审计记录(数据带出操作必须可追溯)。

七、lrzsz(终端传小文件)

bash
yum install lrzsz -y
apt install lrzsz -y

# 上传:弹出文件选择框
rz

# 下载:弹出保存路径
sz /tmp/debug.log

依赖终端客户端支持 ZMODEM,Xshell、SecureCRT、iTerm2 支持;Web Terminal、VS Code 内置终端等不支持。

只适合临时传小文件。正式发布包走 rsync 或堡垒机。

八、常见问题

Permission denied(两段区分)

text
# SSH 认证层拒绝——没连上
Permission denied (publickey,password).

# 文件系统层拒绝——连上了但写不了
scp: dest open "/etc/myapp/app.conf": Permission denied

文件系统层拒绝的处理:

bash
# 先传到 /tmp,再 sudo 移动
scp ./app.conf user@host:/tmp/app.conf

ssh user@host 'sudo install -m 0644 -o root -g root /tmp/app.conf /etc/myapp/app.conf'

install 命令比 mv 更安全——移动的同时设置权限和属主。

传输中断

bash
# scp 中断→重头传。大文件用 rsync -P
rsync -avP ./bigfile.tar.gz root@host:/data/

-P 保留已接收的部分,重跑自动续传。

文件名空格

服务器上命名用 -_ 替代空格,避免引号和转义问题:

bash
scp "./app config.conf" root@host:/tmp/

Windows 脚本的换行符

bash
# Windows 编辑的脚本传到 Linux:开头 /bin/bash^M → bad interpreter
# 查看行尾
file deploy.sh

# 转换
dos2unix deploy.sh

传输前先备份

覆盖配置前,先在远端用时间戳备份:

bash
ssh root@host 'cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%F-%H%M%S).bak'