今天需要上传文件到服务器,但是文件数量巨大且文件容量极小。如果用传统的SCP速度极慢,所以准备用scp传输.gz压缩文件到服务器,然后在服务器上解压。

但是!scp 命令是基于 ssh 协议的,既然可以用 ssh ,还要什么 scp 呢!

我们可以直接用 ssh 就可以传输文件,学会了之后,发现它比 scp 还好用,scp 的 path 写起来比较蛋疼。

首先很多人忽略的一个事实是,ssh 可以直接输入命令对远程主机执行,比如 ssh root@myserver.com "cat access.log" ,就可以直接 cat 出远程文件的 log 内容。ssh 会将远程命令的 stdout 和本地的 stdout 连接起来。可以用这样的命令来看实时的日志: ssh root@myserver.com "tail -f access.log"。这样就可以在本地执行一条命令就可以了,方便脚本化或记录到 本地 history。

既然 ssh 可以将 stdout 连接起来,那么自然也可以将 stdin 连接起来!比如用这个命令将 ssh key 拷贝到服务器上去。

1
cat ~/.ssh/id_rsa.pub \| ssh root@myserver.com "cat - >> .ssh/authorized_keys"

将一个文件传输到服务器:

1
cat myfile \| ssh root@myserver.com "cat - > /tmp/myfile"

上面这个命令的原理就是,将文件内容输入到 stdout 中,用管道和 ssh 连接起来,然后这个 stdout 就成了远程命令的 stdin。

img

要拷贝整个文件夹呢?没有问题:

1
tar c . \| ssh root@myserver.com "tar xv"

如果是像日志这种压缩性能很高的文件,可以考虑压缩之后再传输,远程那边从 stdin 解压缩。而且直接将输入和输出通过管道连接起来,压缩中间生成的文件丝毫不会占用空间呢!

1
tar cz . \| ssh sit.takachiho "tar xzv"

如果要指定远程的目标文件夹,可以使用 tar 的 C 参数来指定,比如远程解压缩到 /tmp 下面:

1
tar cz . \| ssh sit.takachiho "tar xzvC /tmp"

要注意像图片、视频这种二进制文件,本身就是经过压缩之后的了,如果再使用 tar z 来压缩一遍的话,不会节省多少传输体积,反而会白白耗费 CPU。

实用技巧:如果每天备份 MySQL 到另一台机器,但是不占用本机空间?Crontab 的脚本这么写:

1
mysqldump --single-transaction -u backuper mydb \| ssh root@backup.myserver.com "cat - > /var/mysql_back.sql"

假如一台机器A在一个网络环境,另一个机器B在另一个网络环境,他们之间不互通。但是你的电脑(或堡垒机)能同时用 ssh 登陆两台机器,那么怎么把 Server A 的文件拷贝到 Server B?

img

用两个 ssh!

1
ssh root@serverA "cat file" \| ssh root@serverB "cat - > /tmp/file"

理解 ssh 能连接 stdin 和 stdout 了,就有无限的可能了!而且你可以将脚本都放在本地,不用还得本地放一些,远程的机器放一些通过 ssh 来执行。

哦对了,ssh 是一个加密的协议,所以在传输的过程中会看到 CPU 使用上涨,因为这是在加密和(远程服务器)解密。用的时候需要考虑到这个。scp 命令是基于 ssh 的,所以会有一样的问题。

nc 基于 tcp 明文传输的,如果不需要加密,传输内容比较多,可以考虑用这个。

在 Server 端执行 nc 监听端口,将输入到 nc 的内容输出到一个文件中。

1
nc -l -p 1234 -q 1 > something.zip < /dev/null

然后在 Client 端将要发送的文件输入到服务器的这个端口中:

1
cat something.zip \| netcat server.ip.here 1234