使用Expect脚本自动从远程下载文件

引言

最近有点想法,很多大文件用本地网络下载很慢,毕竟只有100M带宽;所以想投机取个巧,到vultr上的vps下载文件,毕竟是1000M带宽,然后下载好之后再用scp传到本地。
但是有一点不一样的是,要登录然后再写scp root@...很麻烦,所以我想,用sh脚本可以自动执行啊。
于是,昨晚看了一点bash脚本语言,诸如echo$甚至<< EOF这些,但是像ssh这样的命令在ubuntu中是无法直接交互的,只能通过expect语言(我理解为bash的可交互版)。所以,今天装了一下,尝试一下。

不过,其实还有很多想法想去实现,比如,tomcat的前端后端啊这些的,不过能力有限;而且想捣鼓的太多,反而会散而不精了。

哦,还有,matlab下调用python,这个我还没有看。

一点bash介绍

bash其实就是打开ubuntu终端后输入的一些命令,如sudo apt-get updatecd /home/yann/downloads啊这些的。但是这些都是需要一句句输入的,所以尤其对于那些重复使用的命令,为了减少工作量,可以采用将所有命令写入脚本,然后执行脚本文件。这样,一劳永逸吧!
举例,连续执行两条python运行命令,结束后打印Command completed!:

#! /usr/bin/bash
python /home/yann/Codes/SegNet/Scripts/compute_bn_statistics.py /home/yann/Codes/SegNet/Models/segnet_train.prototxt /home/yann/Codes/SegNet/Models/Training/1_3/_iter_50000.caffemodel /home/yann/Codes/SegNet/Models/Training/1_3/Inference/
# above is for BN
python /home/yann/Codes/SegNet/Scripts/test_segmentation_camvid.py --model /home/yann/Codes/SegNet/Models/segnet_inference.prototxt --weights /home/yann/Codes/SegNet/Models/Training/1_3/Inference/test_weights.caffemodel --iter 20
echo "Command completed!"

再举例,${a}调用变量然后打印出来。

#! /usr/bin/bash
# NOTE
# 必须用双引号 不能用单引号
# 赋值等于号左右都不能有空格
# 取用变量前面必须加$ 最好用${a}这样的形式
a="hello test"
echo "----------------------"
echo "hello world ${a}"

再再举例,执行sudo时,是不能用echo的方式输入的,那么如何输入密码?

#! /usr/bin/bash
# 第一种方法,管道方式,用`<<EOF xxxx EOF `的方式读取sudo密码, 注意此时sudo后面需要 -S
sudo -S apt-get update << EOF
1234
EOF
# 第二种方法,文本重定向方式,用` echo xxxx | `的方式读取sudo密码, 同样注意此时sudo后面需要 -S
echo 1234 | sudo -S apt-get update

参考链接: ubuntu运行sh脚本sudo自动输入密码

尽管以上几条命令能满足大多数的脚本需求,但是,我的目的是sshscp啊。所以,只能通过expect

ubuntu安装expect

sudo apt-get install tcl tk expect
是的,需要装个包,但是就一行。

使用expect

搞了一中午,终于弄好了,通过ssh进入远程vps终端,然后进入/home/yan目录通过wget ××××方式下载文件;然后退出远程,scp执行远程文件传输,将文件拉到本地来。
美滋滋。以后下文件,只要改改变量参数,运行一下就可以了。

首先明确的是,expectbash地位相同。

  • 新建文件yanng
  • 编写程序首行#! /usr/bin/expect
  • 掌握set variable "value"用法,用于设置变量 并为变量传值
  • 掌握spawn ssh root@ss.yanng.cc用法, spawn用于新建进程
  • 掌握expect "*#"用法,expect命令用于查看当前交互结果是否满足
  • 掌握send cd /home/yan用法,send用于在交互时将字符串发送给expect控制的进程
  • 掌握expect eof用法,结束一个进程
  • 掌握exit用法,退出脚本文件

源代码共享

以下脚本实现执行ssh和scp复制操作。

#! /usr/bin/expect
# NOTE: 通过`expect ×××× `方式执行该脚本文件,或者加权限,然后`./xxxx`执行。 都行
# 以下为设置链接 密码和文件名变量 并设置超时等待为一直等待
set link "wget yanng.cc/download/pic.py"
set password "thisispassword"
set filename "pic.py"
set timeout -1
# terminal下执行第一个command,ssh
spawn ssh root@ss.yanng.cc
expect {
"*password:" {send "$password\r";}
"yes/no" {send "yes\r";exp_continue}
}
expect "*#"
send "cd /home/yan\r"
send "$link\r"
send "exit\r"
expect eof
# terminal下执行第二个command,scp
spawn scp root@ss.yanng.cc:/home/yan/${filename} /home/yann/Downloads
expect "*password:"
send "$password\r"
expect eof
exit

结语

以后可以用脚本了,再也不用打那么多命令啦。
努力,努力!

参考链接