引用期望脚本的问题

时间:2016-06-02 04:15:15

标签: expect

我有一个自动连接到VPN的脚本,因为我经常需要每天连接和断开几次。 (某些事情,如ScreenHero和GoToMeeting在VPN上失败,而邮件服务器和其他东西在VPN上被阻止,但是我无法连接到Git服务器,除非我在VPN上,并且我正在处理的应用程序无法访问某些后端服务,除非我在VPN上,因此断开连接时开发受限。)

该脚本减轻了麻烦,但我的密码中有$(通过环境变量VPN_PASSWORD 1 在环境中可用)和密码值在被期望传递给VPN程序之前被插值。

#!/bin/bash

{
  /usr/bin/expect << END_OF_LOGIN_SESSION
  set timeout 30
  spawn /opt/cisco/anyconnect/bin/vpn -s connect blah.blahblah.com
  expect "Username:*"
  send "\r"
  expect "Password:*"
  send "$VPN_PASSWORD\r"
  expect "accept? \[y/n\]:*"
  send "y\r"
  expect eof
END_OF_LOGIN_SESSION
}

如何在不让字符串插值的情况下直接传递密码?

更改密码是个问题。使用\保存它也是一个警察(和可怕的用户体验,因为每次我为此项目 2 提供.project文件时我都必须输入它。

似乎期望必须有一个解决方案。

  1. 是的,我知道窃取我的笔记本电脑的人可能会尝试登录,但是(a)他们必须先进入我的帐户,然后(b)他们在没有我的PIN的情况下失败,通过电话输入,无论如何。

  2. 不,密码不会保存到磁盘。我在每个与此项目相关的shell会话中输入一次。

2 个答案:

答案 0 :(得分:2)

除非您定义了具有该名称的任何变量,否则您应该首先获得can't read "VPN_PASSWORD": no such variable

可以通过Tcl的特殊数组变量env访问环境变量。

您可以直接使用env(VPN_PASSWORD)来访问相同内容。

send "$env(VPN_PASSWORD)\r"

参考: env

答案 1 :(得分:1)

在非加引号的heredoc中有shell变量$VPN_PASSWORD,因此shell将替换该值。假设VPN_PASSWORD='foo$bar' =&gt;然后期望看到:send "foo$bar\r"并且您将获得can't read "bar": no such variable。解决方案是使用{braces}而不是双引号,因此期望尝试扩展&#34;内部&#34;变量

send {$VPN_PASSWORD}; send "\r"

您需要单独的send "\r",因为将\r放在大括号内会删除其特殊含义,而Tcl不会让您send {$VPN_PASSWORD}"\r"

这是一个演示:

$ VPN_PASSWORD='foo$bar'
$ expect <<END
send_user "$VPN_PASSWORD\n"
END
can't read "bar": no such variable
    while executing
"send_user "foo$bar\n""
$ expect <<END
send_user {$VPN_PASSWORD}; send_user "\n"
END
foo$bar

在Tcl中,大括号在shell中就像单引号一样:内部的所有内容都是文字字符。

使用环境传递值可能更清晰。这里它被实现为shell函数

vpnconnect() {
    expect <<'END'
        set timeout 30
        spawn /opt/cisco/anyconnect/bin/vpn -s connect $env(VPN_HOST)
        expect "Username:*"
        send "\r"
        expect "Password:*"
        send "$env(VPN_PASSWORD)\r"
        expect {accept? [y/n]:*}
        send "y\r"
        expect eof
END
}