WB
WB
文章目录
  1. 1. 前言
  2. 2. 脚本语言也可以
    1. 2.1. Python
    2. 2.2. PHP
  3. 3. 鲜为人知的 nc
    1. 3.1. 监听端口
    2. 3.2. 发送数据
    3. 3.3. 说明
  4. 4. 虚拟终端软件中的rz 和 sz
    1. 4.1. rz 命令
    2. 4.2. sz 命令
    3. 4.3. 说明
  5. 5. 传统的sftp和ftp
    1. 5.1. 上传文件
    2. 5.2. 下载文件
    3. 5.3. 退出
    4. 5.4. 说明
  6. 6. 功能专一的scp
    1. 6.1. 把本地文件复制到远程
    2. 6.2. 把远程机器上的文件复制到本地
    3. 6.3. 上传目录使用-r
    4. 6.4. 说明
  7. 7. 增量同步的神:rsync
    1. 7.1. 不带任何选项
    2. 7.2. 同步文件类型
    3. 7.3. 同步文件属性
    4. 7.4. 复合命令
    5. 7.5. 用户体验
    6. 7.6. 控制同步策略
  8. 8. 总结
  9. 9. 参考文档

远程传输文件的命令

前言

若干年前,我曾对面试者问出过一个类似的问题:有哪些远程传输文件的命令?

他的回答令我非常意外:

  • 答:使用rzsz

  • 我:如果没有xshell之类的软件呢?

  • 答:那就下载一个

  • 我:emmmm…….,还有其他命令么?

  • 答:不会了

  • 我:emmmm…….

虽然标题里的千千万有些夸张,但跨主机传输文件的命令可是真不少的。下面就来介绍些我曾经用过的那些文件传输命令吧!

脚本语言也可以

很多脚本语言都可以临时启动一个http server。于是我们便可以通过浏览器来下载一些文件

Python

Python可以临时启动一个http server来提供文件访问

Python 2

1
2
$ python -m SimpleHTTPServer 8000
复制代码

Python 3

1
2
$ python3 -m http.server 8000
复制代码

通过浏览器我们就可以看到目录可以进行下载

PHP

启动php内置的服务器之后,虽然我们没有办法通过浏览器来浏览目录,但可以直接通过浏览器下载文件

1
2
3
$ php -S 0.0.0.0:8000 
[Mon Feb 20 15:04:35 2023] PHP 7.4.27 Development Server (http://0.0.0.0:8000) started
复制代码

鲜为人知的 nc

ncnetcat的简写,有着网络界的瑞士军刀美誉。因为它短小精悍、功能实用,被设计为一个简单、可靠的网络工具

很多人只知道nc可以用来探测端口是否打开,功能和telnet类似

1
2
3
4
5
6
$ nc -v 192.168.199.226 1001
nc: connectx to 192.168.199.226 port 1001 (tcp) failed: Connection refused

$ nc -v 192.168.199.226 1000
Connection to 192.168.199.226 port 1000 [tcp/cadlock2] succeeded!
复制代码

但不知道nc也可以进行端口监听!利用nc端口监听的功能我们就可以实现文件传输

监听端口

在目标机器上监听端口,并使用管道输出到某文件。注意:下面的-l是小写的L,不是数字1

1
2
$ nc -l 1000 > dst/main.go
复制代码

发送数据

在本地机器上执行

1
2
3
$ nc -v 192.168.199.226 1000 < source/main.go
Connection to 192.168.199.226 port 1000 [tcp/cadlock2] succeeded!
复制代码

source/main.go就被传输到了192.168.199.226的机器上,并且文件名为dst/main.go

说明

nc进行文件传输,功能非常简陋,能做的事情不多,但不失为没有其他命令时的应急方案

上面两种方式只能上传或者下载文件,下面来介绍些既可以上传又可以下载的玩法

虚拟终端软件中的rzsz

当我们使用虚拟终端软件,如Xshell、SecureCRT或PuTTY来连接远程服务器后,可以使用rzsz来上传下载文件

rz 命令

使用rz命令可以上传本地文件到远程服务器。运行该命令会弹出一个文件选择窗口,从本地选择文件上传到Linux服务器

sz 命令

将选定的文件发送到本地机器。运行该命令会弹出一个文件选择窗口,从Linux服务器发送到本地(保存的目录是可以配置)

说明

rz命令与sz命令常用在虚拟终端软件中,如果是在两台linux直接传输文件,往往是不可行的

传统的sftpftp

sftpftp有着几乎一样的语法和功能,sftp是一个独立的SSH封装协议包,通过安全连接以相似的方式工作。这意味着只要目标端启动了sshd服务器就可以使用sftp,而且是一种安全传输文件的方式,因此我更推荐你使用sftp

要连接到远程 sftp 服务器,如下建立一个安全 SSH 连接并创建 SFTP 会话:

1
2
$ sftp wentao@192.168.199.151
复制代码

登录到远程主机后,你可以如下运行交互式的 sFTP 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sftp> ls -al  # 展示远程主机文件列表
drwxr-xr-x 6 wentao wheel 192 Feb 19 18:35 .
drwxrwxrwt 13 root wheel 416 Feb 19 18:26 ..
-rw-r--r-- 1 wentao wheel 73 Feb 19 18:35 main.go
drwxr-xr-x 6 wentao wheel 192 Feb 19 18:35 sub

sftp> pwd # 远程主机当前路径
Remote working directory: /private/tmp/dst

sftp> lls -al # 展示本地主机文件列表
total 8
drwxr-xr-x 6 wentao wheel 192 Feb 19 16:54 .
drwxrwxrwt 9 root wheel 288 Feb 19 18:29 ..
-rw-r--r-- 1 wentao wheel 0 Feb 19 18:30 a
-rw-r--r-- 1 wentao wheel 73 Feb 19 18:30 main.go
drwxr-xr-x 6 wentao wheel 192 Feb 19 18:25 sub

sftp> lpwd # 本地主机当前路径
Local working directory: /private/tmp/source
复制代码

上传文件

把本地当前路径下的main.go上传到远程主机当前路径

1
2
3
4
sftp> put main.go
Uploading main.go to /private/tmp/dst/main.go
main.go
复制代码

把本地当前路径下的main.go上传到远程主机当前路径,并命名成a.go

1
2
3
4
sftp> put main.go a.go
Uploading main.go to /private/tmp/dst/a.go
main.go
复制代码

下载文件

把远程主机当前路径下的main.go下载到本地当前路径

1
2
3
4
sftp> get main.go
Fetching /private/tmp/dst/main.go to main.go
main.go
复制代码

依旧可以自定义名字

1
2
3
4
sftp> get main.go a.go
Fetching /private/tmp/dst/main.go to a.go
main.go
复制代码

退出

退出sftp shell可以输入 !

1
2
sftp> !
复制代码

说明

还有许多图形界面甚至是语言SDK支持sftp,它的目标不仅仅是传输文件,是历史非常悠久的文件管理协议

功能专一的scp

scp消耗资源少,功能专一,并且加密传输,可以说是最常用的跨主机复制命令。

cp的命令相似,scp的使用非常简单

1
2
scp [参数] [原路径] [目标路径]
复制代码
  • 第一个路径是原路径,第二个是目标路,两者都可以是远程机器
  • 路径:ssh命令一样,使用@符分割用户名和ip,同时使用:连接目标目录

把本地文件复制到远程

1
2
$ scp source/main.go wentao@192.168.199.151:/tmp/dst/
复制代码

把远程机器上的文件复制到本地

1
2
$ scp wentao@192.168.199.151:/tmp/dst/main.go source/
复制代码

上传目录使用-r

1
2
$ scp -r source/* wentao@192.168.199.151:/tmp/dst/
复制代码

说明

scp在小文件场景下确实得心应手,但面对大文件或者网络不好需要续传的场景,scp的效率就会受到较大的影响了。此时就是另一个命令的大显身手的时候了。

增量同步的神:rsync

rsync是一种快速且非常通用的文件复制工具。它使用增量传输算法,该算法仅发送源文件和目标文件之间的差异以减少网络发送的数据量。所以它广泛用于备份和镜像,或作为日常使用的拷贝命令

不带任何选项

我们可以使用rsync进行本地复制

1
2
rsync main.go wentao@192.168.199.151:/tmp/dst
复制代码

或者把本地文件复制到远程。和ssh命令一样,使用@符分割用户名和ip,同时使用:连接目标目录

1
2
rsync main.go wentao@192.168.199.151:/tmp/dst
复制代码

或者把远程机器上的文件复制到本地

1
2
rsync wentao@192.168.199.151:/tmp/source/main.go /tmp/dst
复制代码

只要目的端的文件内容和源端不一样,并且对源文件的读权限,对目标路径有写权限,就会触发数据同步,rsync就能确保目的端文件同步到和源端一致。(⚠️ 注意是同步文件)

✨【quick check】rsync很聪明,它对两边时间戳和文件大小一致的文件将不会采取更新动作。但聪明有时也反被聪明误,如果目的端文件的时间戳、大小和源端完全一致,但是内容恰巧不一致时,rsync是发现不了的

✨【modify time】rsync不会同步文件的modify time,凡是有数据同步的文件,目的端的文件的modify time总是会被修改为最新时刻的时间

✨【rwx权限】rsync不会关注目的端文件的rwx权限,如果目的端没有此文件,那么权限会保持与源端一致;如果目的端有此文件,则权限不会随着源端变更

✨【用户和组】rsync只能以登陆目的端的账号来创建文件,它没有能力保持目的端文件的用户和用户组和源端一致。(除非你使用root权限,才有资格要求用户一致、用户组一致)

✨【删除策略】rsync只确保源目录(使用-r,下文会讲)的所有内容都复制到目标目录,并且不会删除目标目录的文件

同步文件类型

🌲 -r , --recursive:同步文件夹

当我们不加选项的同步一个文件夹时,rsync会跳过其中的文件夹,仅同步文件

1
2
3
4
5
6
7
8
9
10
# 跳过了source中的sub文件夹
$ rsync -v source/* wentao@192.168.199.151:/tmp/dst
skipping directory source/sub
a
main.go

# source都跳过了
$ rsync -v source wentao@192.168.199.151:/tmp/dst
skipping directory source
复制代码

加上-r选项,指示需要递归所有文件夹一起同步

1
2
3
4
5
6
7
$ rsync -vr source  wentao@192.168.199.151:/tmp/dst
building file list ... done
source/a
source/main.go
source/sub/
source/sub/c
复制代码

🌲 -l, --links:同步软链接文件

如果我们要同步一个软链接文件,你猜rsync会提示什么?

1
2
3
4
5
6
7
8
$ ll source/
total 0
lrwxr-xr-x 1 wentao wheel 9B Feb 18 21:19 d -> outsync/d
-rw-r--r-- 1 wentao wheel 0B Feb 18 20:08 main.go

$ rsync source/d wentao@192.168.199.151:/tmp/dst
skipping non-regular file "d"
复制代码

你猜对了,rsync又无情了拒绝了我们。它一旦发现某个文件是软链接,就会无视它,除非我们增加-l选项。

1
2
$ rsync -l source/d  wentao@192.168.199.151:/tmp/dst
复制代码

使用了-l选项后,rsync会完全保持软链接文件类型,原原本本的将软链接文件复制到目的端,而不会“follow link”到指向的实体文件。

示例中,虽然软链接文件被同步过去了,但因为软连接指向的文件并没有,所以自然会提示No such file or directory

1
2
3
4
5
6
7
8
9
10
# wentao@192.168.199.151
➜ dst ll
total 0
-rw-r--r-- 1 wentao wheel 0B Feb 18 20:35 a
-rw-r--r-- 1 wentao wheel 0B Feb 18 20:24 b
lrwxr-xr-x 1 wentao wheel 9B Feb 18 21:20 d -> outsync/d

➜ dst cat d
cat: d: No such file or directory
复制代码

如果我偏偏就想让rsync采取”follow link”的方式,那就用-L选项就可以了

1
2
$ rsync -vv -L source/d  wentao@192.168.199.151:/tmp/dst
复制代码

此时目标端已经不再时软连接文件了,而是实体文件

1
2
3
4
5
6
➜  dst ll
total 0
-rw-r--r-- 1 wentao wheel 0B Feb 18 20:35 a
-rw-r--r-- 1 wentao wheel 0B Feb 18 20:24 b
-rw-r--r-- 1 wentao wheel 0B Feb 18 21:34 d
复制代码

🌲 --devices:同步块设备文件

块设备也能被同步,但前提是目标端使用super-user用户传输

🌲 --specials:同步特殊文件

特殊文件主要包含着命名socketsfifos

同步文件属性

🌲 -p, --perms:同步权限

还记得无选项时提到的rwx权限么?

  • 如果目的端没有此文件,那么在同步后会将目的端文件的权限保持与源端一致

  • 如果目的端已存在此文件,那么只会同步文件内容,权限保持原有不变

如果你使用了-p选项,则无论如何,rsync都会让目的端保持与源端的权限一致的

🌲 -t, --times:同步修改时间

还记得无选项时提到的modify time么?rsync不会同步文件的modify time,凡是有数据同步的文件,目的端的文件的modify time总是会被修改为最新时刻的时间

如果你使用了-t选项,则无论如何,rsync都会让目的端保持与源端的修改时间一致的

🌲 -g, --group:同步文件用户组

🌲 -o, --owner:同步文件用户

还记得无选项时提到的用户和组么?rsync只能以登陆目的端的账号来创建文件,它没有能力保持目的端文件的用户和用户组和源端一致

这两个选项是一对,用来保持文件的属组(group)和属主(owner),作用应该很清晰明了。不过要注意的一点是,改变属主和属组,往往只有管理员权限才可以

复合命令

🌲-a, --archive: -rlptgoD

-a选项,就相当于使用了-rlptgoD这一坨选项,以一敌七。(在看了前文之后,你应该可以很轻松的理解这七个选项的作用了)

  • -r , --recursive:同步文件夹
  • -l, --links:同步软链接文件
  • -p, --perms:同步权限
  • -t, --times:同步修改时间
  • -g, --group:同步文件用户组
  • -o, --owner:同步文件用户
  • -D: 等同于 --devices --specials
    • --devices:同步块设备文件
    • --specials:同步特殊文件

用户体验

🌲-v, --verbose:展示日志信息

这个选项简单易懂,就是让rsync输出更多的信息,我们可以举一个例子:

1
2
3
4
5
6
$ rsync -v main.go wentao@192.168.199.151:/tmp/dst
main.go

sent 84 bytes received 42 bytes 252.00 bytes/sec
total size is 0 speedup is 0.00
复制代码

增加越多的v,就可以获得越多的日志信息。

1
2
3
4
5
6
7
8
9
10
11
12
$ rsync -vvvv main.go wentao@192.168.199.151:/tmp/dst
cmd= machine=192.168.199.151 user=wentao path=/tmp/dst
cmd[0]=ssh cmd[1]=-l cmd[2]=wentao cmd[3]=192.168.199.151 cmd[4]=rsync cmd[5]=--server cmd[6]=-vvvv cmd[7]=. cmd[8]=/tmp/dst
opening connection using ssh -l wentao 192.168.199.151 rsync --server -vvvv . /tmp/dst
(Server) Protocol versions: remote=29, negotiated=29
(Client) Protocol versions: remote=29, negotiated=29
[sender] make_file(main.go,*,2)
server_recv(2) starting pid=3420
[sender] i=0 <NULL> main.go mode=0100644 len=0 flags=0
send_file_list done
...
复制代码

🌲 -n, --dry-run:不实际执行

如果担心执行删除等危险操作时误操作,可以使用-n进行测试

加上-n之后并不会真正执行同步,与-v搭配则会展示rsync要如何操作每一个文件

1
2
3
4
5
6
$ rsync -n -v --delete -r source/ wentao@192.168.199.151:/tmp/dst
building file list ... done
deleting b
a
main.go
复制代码

控制同步策略

🌲 -I, --ignore-times:不使用quick check

还记得无选项时提到的quick check么?rsync会忽略两边时间戳和文件大小一致的文件,以提高传输速度,但有时却会产生问题

1
2
$ rsync -I source/main.go  wentao@192.168.199.151:/tmp/dst
复制代码

-I选项会让rsync变得很乖很老实,它会挨个文件去发起数据同步

-I选项可以确保数据的一致性,代价便是速度上会变慢,因为我们放弃了“quick check”策略

🌲 --delete:删除目标的文件

还记得无选项时提到的删除策略么?如果在源端删除了某文件,目的端是不会被删除的

当使用了 --delete之后,如果源端没有此文件,那么发送方也别想拥有,删除之。(如果你使用这个选项,就必须搭配-r选项一起)

🌲 -z, --compress:压缩传输

这是个压缩选项,只要使用了这个选项,rsync就会把发向对端的数据先进行压缩再传输,从而减小数据量

对于网络环境较差的情况下建议使用

总结

通过介绍的内容占比大家也可以看出来,我最爱的命令是rsync,但我并不是所有场景都使用它

我最常用的其实是scp。首先它非常简单,消耗资源少,而且大部分linux发行版都自带这个命令

但当要传输非常大或者非常多的文件,或者网络环境不太好的时候,我更喜欢rsync。它使用增量同步的方案,支持压缩,因此传输非常快,而且断线之后还可以续传

当主机上没有这两个命令时,我才会尝试使用 sfptnc、或者脚本语言等方式

你还知道哪些跨主机文件传输的命令或者方式呢?欢迎评论区留言讨论~

参考文档

支持一下
扫一扫,支持一下
  • 微信扫一扫
  • 支付宝扫一扫