美文网首页编程之路
使用 expect 上传静态资源到服务器

使用 expect 上传静态资源到服务器

作者: 皱巴巴 | 来源:发表于2018-10-23 15:59 被阅读4次

    前段时间写了一篇Node.js 静态资源打包上传脚本的博客,今天又花了些时间使用 expect 编写了一版。主要完成静态资源打包、上传到服务器、解压到服务器指定目录的功能。

    expect 介绍

    Expect 是 Unix 系统中用来进行自动化控制和测试的软件工具,作为Tcl脚本语言的一个扩展,应用在交互式软件中如 telnet,ftp,Passwd,fsck,rlogin,tip,ssh 等等。该工具利用 Unix 伪终端包装其子进程,允许任意程序通过终端接入进行自动化控制;也可利用Tk工具,将交互程序包装在 X11 的图形用户界面中。

    维基百科

    expect 主要命令

    • spawn 新建一个进程,这个进程的交互由 expect 控制。
    • expect 等待接受进程返回的字符串,直到超时时间,根据规则决定下一步操作。
    • send 发送字符串给expect控制的进程。
    • set 设定变量为某个值。
    • exp_continue 重新执行expect命令分支。
    • [lindex $argv 0] 获取expect脚本的第 1 个参数。
    • interact 将脚本的控制权交给用户,用户可继续输入命令。
    • expect eof 等待 spawn 进程结束后的退出信号 eof。

    基本用法

    一个简单地自动 SSH 远程服务器例子如下:

    #!/usr/bin/expect  // 1
    
    set timeout 20 // 2
    
    spawn ssh root@192.168.1.1 // 3
    expect "*password:" // 5
    send "123\r" // 6
    
    interact // 7
    
    1. 告诉操作系统执行此脚本时使用哪个解释器。
    2. 设置 timeout 变量,此变量用于执行命令执行的超时时间,如果 expect 某个命令的输出时,超过了指定的时间,expect 就执行下面的代码。
    3. 新建一个进程,执行 ssh 命令。
    4. 等待 ssh 命令的返回结果,期望输出信息匹配 *password:,即请求密码。
    5. 发送交互信息,这里发送 123\r,相当于手动输入 “123” 并按下回车。
    6. 脚本执行完后保持互状态,把控制权交给控制台,这个时候就可以手工操作了。

    编写脚本

    目录结构如下:

    .
    ├── dist
    │   ├── index.js
    │   ├── index.html
    │   ├── index.css
    │   ├── ...
    └── upload.exp
    

    dist 目录中是所有的静态资源,脚本的主要工作就是把 dist 中内容上传到服务器中的指定目录下。其中,服务器的 IP、用户名、密码以及指定的目录可以通过参数传入。例如将静态资源上传到 192.168.1.1 服务器的 /root/public 文件夹中,用户名为 root,密码为 root

    $ expect upload.exp 192.168.1.1 root root /root/public
    

    创建脚本文件

    创建与 dist 目录同级的 upload.exp 文件,并在文件第一行指定解释器:

    #!/usr/bin/env expect
    

    这里没有使用上面实例中的 #!/usr/bin/expect 是为了防止用户没有把 expect 装在默认的 /usr/bin 中。

    读取参数

    使用 [lindex $argv] 读取参数:

    set host [lindex $argv 0]
    set username [lindex $argv 1]
    set password [lindex $argv 2]
    set target [lindex $argv 3]
    

    打包静态资源

    为了便于上传到服务器中,首先调用 tar 命令将资源打包,这里需要注意的时,在打包时不应该把 dist 目录打包进去,而是打包 dist 目录下面的内容,否则解压时会多出 dist 目录。我们可以通过 -C 参数指定工作目录为 dist,然后打包当前目录下的内容即可:

    spawn tar -czvf dist.tar.gz -C dist .
    

    然后加上 expect eof 等待 spawn 进程结束。

    上传压缩包到服务器

    打包完毕后,调用 scp 命令将压缩包上传到服务器上的指定目录中,这里需要使用之前读取到的参数:

    spawn scp dist.tar.gz $username@$host:$target
    

    上传到服务器时需要输入账户密码:

    expect {
      "(yes/no)?"  {
        send "yes\r"
        expect "*assword:" {
          send "$password\r"
        }
      }
      "*assword:"  {
        send "$password\r"
      }
    }
    

    这里需要匹配 (yes/no)? 是因为有时候连接服务器(通常是第一次)会出现提示信息,需要确认是否继续连接:

    The authenticity of host '111.222.333.444 (111.222.333.444)' can't be established.
    RSA key fingerprint is f3:cf:58:ae:71:0b:c8:04:6f:34:a3:b2:e4:1e:0c:8b.
    Are you sure you want to continue connecting (yes/no)? 
    

    上传完毕后,会显示进度为 100%,通过 expect 匹配此输出,表明上传完成:

    expect "100%"
    

    连接服务器执行远程命令

    压缩包上传成功后,我们需要连接到远程服务器,在服务器上进行解压操作。使用 ssh 命令连接服务器,并处理密码:

    spawn ssh $username@$host
    
    expect {
      "(yes/no)?"  {
        send "yes\r"
        expect "*assword:" {
          send "$password\r"
        }
      }
      "*assword:"  {
        send "$password\r"
      }
    }
    

    连接到终端后,我们需要匹配远程终端的提示信息:

    root@iZ2zeck1ad0ao2rjwcs6u7Z:~$
    

    通过 expect -re "~.*(#|$)"。其中 -re 参数表明后面是一个正则表达式。如果匹配此信息,表明成功连接上了远程终端。

    接着,我们发送远程解压命令即可:

    send "tar -zxvf $target_path/dist.tar.gz -C $target_path\r"
    

    解压完成后,可以删除压缩包:

    send "rm -r $target_path/dist.tar.gz\r"
    

    完整脚本

    #!/usr/bin/env expect
    
    set host [lindex $argv 0]
    set username [lindex $argv 1]
    set password [lindex $argv 2]
    set target [lindex $argv 3]
    
    set cmd_prompt "~.*(#|$)"
    
    # 打包
    spawn tar -czvf dist.tar.gz -C dist .
    
    # 上传
    expect eof
    spawn scp dist.tar.gz $username@$host:$target
    
    expect {
      "(yes/no)?"  {
        send "yes\r"
        expect "*assword:" {
          send "$password\r"
        }
      }
      "*assword:"  {
        send "$password\r"
      }
    }
    expect "100%"
    send_user "\n"
    
    # SSH
    spawn ssh $username@$host
    
    expect {
      "(yes/no)?"  {
        send "yes\r"
        expect "*assword:" {
          send "$password\r"
        }
      }
      "*assword:"  {
        send "$password\r"
      }
    }
    
    # 解压
    expect -re $cmd_prompt
    send "tar -zxvf $target/dist.tar.gz -C $target\r"
    
    # 删除压缩包
    expect -re $cmd_prompt
    send "rm -r $target/dist.tar.gz\r"
    
    expect -re $cmd_prompt
    exit
    

    相关文章

      网友评论

        本文标题:使用 expect 上传静态资源到服务器

        本文链接:https://www.haomeiwen.com/subject/iksazftx.html