期望脚本的引用问题
Quoting issue with expect script
我有一个自动连接到 VPN 的脚本,因为我经常需要一天连接和断开几次。 (ScreenHero 和 GoToMeeting 等某些东西在 VPN 上失败,邮件服务器和其他东西在 VPN 上被阻止,但是我无法连接到 Git 服务器,除非我在 VPN 上,除非我在 VPN 上,否则我正在开发的应用无法访问某些后端服务,因此在断开连接时开发会受到限制。)
该脚本减少了麻烦,但我的密码中有一个 $
(可通过环境变量 VPN_PASSWORD
1 在环境中使用) ), 并且密码值在通过 expect 传递给 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[=37= 获取我的 .project
文件时我都必须输入它]).
看来expect一定有解决办法。
是的,我知道有人偷了我的笔记本电脑可以尝试登录,但是 (a) 他们必须先进入我的帐户,并且 (b) 如果没有我的 PIN,他们会失败,由 phone 输入,无论如何。
不,密码没有保存到磁盘。我在与该项目相关的每个 shell 会话中输入一次。
除非您定义了具有该名称的任何变量,否则您应该首先获得 can't read "VPN_PASSWORD": no such variable
。
可以通过Tcl的特殊数组变量访问环境变量env
。
您可以直接使用 env(VPN_PASSWORD)
访问相同的内容。
send "$env(VPN_PASSWORD)\r"
参考: env
您在未加引号的 heredoc 中有 shell 变量 $VPN_PASSWORD
,因此 shell 将替换该值。假设 VPN_PASSWORD='foo$bar'
=> 那么 expect 会看到:send "foo$bar\r"
并且你会得到 can't read "bar": no such variable
。解决方案是使用 {braces}
而不是双引号,这样 expect 将 不会 尝试扩展 "inner" 变量。
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
}
我有一个自动连接到 VPN 的脚本,因为我经常需要一天连接和断开几次。 (ScreenHero 和 GoToMeeting 等某些东西在 VPN 上失败,邮件服务器和其他东西在 VPN 上被阻止,但是我无法连接到 Git 服务器,除非我在 VPN 上,除非我在 VPN 上,否则我正在开发的应用无法访问某些后端服务,因此在断开连接时开发会受到限制。)
该脚本减少了麻烦,但我的密码中有一个 $
(可通过环境变量 VPN_PASSWORD
1 在环境中使用) ), 并且密码值在通过 expect 传递给 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[=37= 获取我的 .project
文件时我都必须输入它]).
看来expect一定有解决办法。
是的,我知道有人偷了我的笔记本电脑可以尝试登录,但是 (a) 他们必须先进入我的帐户,并且 (b) 如果没有我的 PIN,他们会失败,由 phone 输入,无论如何。
不,密码没有保存到磁盘。我在与该项目相关的每个 shell 会话中输入一次。
除非您定义了具有该名称的任何变量,否则您应该首先获得 can't read "VPN_PASSWORD": no such variable
。
可以通过Tcl的特殊数组变量访问环境变量env
。
您可以直接使用 env(VPN_PASSWORD)
访问相同的内容。
send "$env(VPN_PASSWORD)\r"
参考: env
您在未加引号的 heredoc 中有 shell 变量 $VPN_PASSWORD
,因此 shell 将替换该值。假设 VPN_PASSWORD='foo$bar'
=> 那么 expect 会看到:send "foo$bar\r"
并且你会得到 can't read "bar": no such variable
。解决方案是使用 {braces}
而不是双引号,这样 expect 将 不会 尝试扩展 "inner" 变量。
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
}