前言
若干年前,我曾对面试者问出过一个类似的问题:有哪些远程传输文件的命令?
他的回答令我非常意外:
答:使用
rz
或sz
我:如果没有
xshell
之类的软件呢?答:那就下载一个
我:emmmm…….,还有其他命令么?
答:不会了
我:emmmm…….
虽然标题里的千千万有些夸张,但跨主机传输文件的命令可是真不少的。下面就来介绍些我曾经用过的那些文件传输命令吧!
脚本语言也可以
很多脚本语言都可以临时启动一个http server
。于是我们便可以通过浏览器来下载一些文件
Python
Python
可以临时启动一个http server
来提供文件访问
Python 2
1 | python -m SimpleHTTPServer 8000 |
Python 3
1 | python3 -m http.server 8000 |
通过浏览器我们就可以看到目录可以进行下载
PHP
启动php
内置的服务器之后,虽然我们没有办法通过浏览器来浏览目录,但可以直接通过浏览器下载文件
1 | php -S 0.0.0.0:8000 |
鲜为人知的 nc
nc
是netcat
的简写,有着网络界的瑞士军刀美誉。因为它短小精悍、功能实用,被设计为一个简单、可靠的网络工具
很多人只知道nc
可以用来探测端口是否打开,功能和telnet
类似
1 | nc -v 192.168.199.226 1001 |
但不知道nc
也可以进行端口监听!利用nc
端口监听的功能我们就可以实现文件传输
监听端口
在目标机器上监听端口,并使用管道输出到某文件。注意:下面的-l
是小写的L
,不是数字1
1 | nc -l 1000 > dst/main.go |
发送数据
在本地机器上执行
1 | nc -v 192.168.199.226 1000 < source/main.go |
source/main.go
就被传输到了192.168.199.226
的机器上,并且文件名为dst/main.go
说明
nc
进行文件传输,功能非常简陋,能做的事情不多,但不失为没有其他命令时的应急方案
上面两种方式只能上传或者下载文件,下面来介绍些既可以上传又可以下载的玩法
虚拟终端软件中的rz
和 sz
当我们使用虚拟终端软件,如Xshell、SecureCRT或PuTTY来连接远程服务器后,可以使用rz
或sz
来上传下载文件
rz
命令
使用rz
命令可以上传本地文件到远程服务器。运行该命令会弹出一个文件选择窗口,从本地选择文件上传到Linux服务器
sz
命令
将选定的文件发送到本地机器。运行该命令会弹出一个文件选择窗口,从Linux服务器发送到本地(保存的目录是可以配置)
说明
rz
命令与sz
命令常用在虚拟终端软件中,如果是在两台linux
直接传输文件,往往是不可行的
传统的sftp
和ftp
sftp
与ftp
有着几乎一样的语法和功能,sftp
是一个独立的SSH
封装协议包,通过安全连接以相似的方式工作。这意味着只要目标端启动了sshd服务器
就可以使用sftp
,而且是一种安全传输文件的方式,因此我更推荐你使用sftp
要连接到远程 sftp 服务器,如下建立一个安全 SSH 连接并创建 SFTP 会话:
1 | sftp [email protected] |
登录到远程主机后,你可以如下运行交互式的 sFTP 命令:
1 | ls -al # 展示远程主机文件列表 |
上传文件
把本地当前路径下的main.go
上传到远程主机当前路径
1 | put main.go |
把本地当前路径下的main.go
上传到远程主机当前路径,并命名成a.go
1 | put main.go a.go |
下载文件
把远程主机当前路径下的main.go
下载到本地当前路径
1 | get main.go |
依旧可以自定义名字
1 | get main.go a.go |
退出
退出sftp
shell可以输入 !
1 | ! |
说明
还有许多图形界面甚至是语言SDK支持sftp
,它的目标不仅仅是传输文件,是历史非常悠久的文件管理协议
功能专一的scp
scp
消耗资源少,功能专一,并且加密传输,可以说是最常用的跨主机复制命令。
和cp
的命令相似,scp
的使用非常简单
1 | scp [参数] [原路径] [目标路径] |
- 第一个路径是原路径,第二个是目标路,两者都可以是远程机器
- 路径:
ssh
命令一样,使用@
符分割用户名和ip,同时使用:
连接目标目录
把本地文件复制到远程
1 | scp source/main.go [email protected]:/tmp/dst/ |
把远程机器上的文件复制到本地
1 | scp [email protected]:/tmp/dst/main.go source/ |
上传目录使用-r
1 | scp -r source/* [email protected]:/tmp/dst/ |
说明
scp
在小文件场景下确实得心应手,但面对大文件或者网络不好需要续传的场景,scp
的效率就会受到较大的影响了。此时就是另一个命令的大显身手的时候了。
增量同步的神:rsync
rsync
是一种快速且非常通用的文件复制工具。它使用增量传输算法,该算法仅发送源文件和目标文件之间的差异以减少网络发送的数据量。所以它广泛用于备份和镜像,或作为日常使用的拷贝命令
不带任何选项
我们可以使用rsync
进行本地复制
1 | rsync main.go [email protected]:/tmp/dst |
或者把本地文件复制到远程。和ssh
命令一样,使用@
符分割用户名和ip,同时使用:
连接目标目录
1 | rsync main.go [email protected]:/tmp/dst |
或者把远程机器上的文件复制到本地
1 | rsync [email protected]:/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 | 跳过了source中的sub文件夹 |
加上-r
选项,指示需要递归所有文件夹一起同步
1 | rsync -vr source [email protected]:/tmp/dst |
🌲 -l
, --links
:同步软链接文件
如果我们要同步一个软链接文件,你猜rsync
会提示什么?
1 | ll source/ |
你猜对了,rsync
又无情了拒绝了我们。它一旦发现某个文件是软链接,就会无视它,除非我们增加-l
选项。
1 | rsync -l source/d [email protected]:/tmp/dst |
使用了-l
选项后,rsync
会完全保持软链接文件类型,原原本本的将软链接文件复制到目的端,而不会“follow link”到指向的实体文件。
示例中,虽然软链接文件被同步过去了,但因为软连接指向的文件并没有,所以自然会提示No such file or directory
1 | [email protected] |
如果我偏偏就想让rsync
采取”follow link”的方式,那就用-L
选项就可以了
1 | rsync -vv -L source/d [email protected]:/tmp/dst |
此时目标端已经不再时软连接文件了,而是实体文件
1 | ➜ dst ll |
🌲 --devices
:同步块设备文件
块设备也能被同步,但前提是目标端使用super-user
用户传输
🌲 --specials
:同步特殊文件
特殊文件主要包含着命名sockets
和fifos
同步文件属性
🌲 -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 | rsync -v main.go [email protected]:/tmp/dst |
增加越多的v
,就可以获得越多的日志信息。
1 | rsync -vvvv main.go [email protected]:/tmp/dst |
🌲 -n, --dry-run
:不实际执行
如果担心执行删除等危险操作时误操作,可以使用-n
进行测试
加上-n
之后并不会真正执行同步,与-v
搭配则会展示rsync
要如何操作每一个文件
1 | rsync -n -v --delete -r source/ [email protected]:/tmp/dst |
控制同步策略
🌲 -I
, --ignore-times
:不使用quick check
还记得无选项时提到的quick check么?rsync
会忽略两边时间戳和文件大小一致的文件,以提高传输速度,但有时却会产生问题
1 | rsync -I source/main.go [email protected]:/tmp/dst |
✨ -I
选项会让rsync
变得很乖很老实,它会挨个文件去发起数据同步
✨ -I
选项可以确保数据的一致性,代价便是速度上会变慢,因为我们放弃了“quick check”策略
🌲 --delete
:删除目标的文件
还记得无选项时提到的删除策略么?如果在源端删除了某文件,目的端是不会被删除的
当使用了 --delete
之后,如果源端没有此文件,那么发送方也别想拥有,删除之。(如果你使用这个选项,就必须搭配-r
选项一起)
🌲 -z
, --compress
:压缩传输
这是个压缩选项,只要使用了这个选项,rsync
就会把发向对端的数据先进行压缩再传输,从而减小数据量
对于网络环境较差的情况下建议使用
总结
通过介绍的内容占比大家也可以看出来,我最爱的命令是rsync
,但我并不是所有场景都使用它
我最常用的其实是scp
。首先它非常简单,消耗资源少,而且大部分linux发行版都自带这个命令
但当要传输非常大或者非常多的文件,或者网络环境不太好的时候,我更喜欢rsync
。它使用增量同步的方案,支持压缩,因此传输非常快,而且断线之后还可以续传
当主机上没有这两个命令时,我才会尝试使用 sfpt
、nc
、或者脚本语言等方式
你还知道哪些跨主机文件传输的命令或者方式呢?欢迎评论区留言讨论~