我通过一个简单的 bash 脚本连接到 VPN,我想在计算机启动时运行该脚本,因此,我需要它完全自动化。但是,该脚本将运行“openconnect --jupiper”并随后询问我的凭据(大约 3-4 秒后,当它获取连接时)。
我想让它在找到一些文本后(最快且更精确的方式)或在设定的延迟后(愚蠢且不太精确的方式)输出我的凭据。
有没有办法在设置的延迟后或返回某些文本(例如正则表达式匹配)后输出命令?
答案1
为了自动化命令,我多年来一直使用预计。模拟交互式会话非常有用,无论是在处理确实需要交互性的顽固命令时,还是在与网络上的活动设备或其他服务器交互时。我仍然用它来登录活动设备,获取一些统计数据并执行自动备份。
Expect 是一个根据脚本与其他交互式程序“对话”的程序。按照脚本,Expect 知道程序可以期待什么以及正确的响应应该是什么。解释性语言提供分支和高级控制结构来指导对话。此外,用户可以在需要时直接进行控制和交互,然后将控制权返回给脚本。
作为示例,我编写了一个用于测试 POP 服务的 Expect 脚本:
#!/bin/sh
# \
exec expect "$0" ${1+"$@"}
set force_conservative 0 ;# set to 1 to force conservative mode even if
;# script wasn't run conservatively originally
if {$force_conservative} {
set send_slow {1 .1}
proc send {ignore arg} {
sleep .1
exp_send -s -- $arg
}
}
set timeout -1
spawn telnet 127.0.0.1 110
match_max 100000
expect {
"Hello" { send -- "USER [email protected]\r"; exp_continue
}
"assword" { send -- "PASS password\r" ; exp_continue
}
"logged" {
send -- "LIST 1\r" ; exp_continue
}
-re "failed|denied" { exit
}
"OK 1" { send -- "QUIT\r"; }
}
根据我与 @cas 的对话,我还想指出,简单的正则表达式期望语言子集对于简短的自动化脚本/[非常]粗糙的原型以及 bash 很有用。
如果需要对输出进行更复杂的处理,则可以/更好地使用另一种编程语言来完成交互式处理。
例如,在Python中,期待,或者甚至在 C 中,使用libexpect或者迷你预期。
最近,随着 DevOps 运动的发展,您还获得了一整套新的[和旧的]框架来自动化系统任务,例如安西布尔,木偶,盐。
然而,它们确实需要学习曲线和更多资源。我个人比较喜欢 Ansible。
答案2
我实际上无法让“openconnect”正确地与所有命令行参数一起工作,所以我最终为其制作了一个 Expect 脚本。
Rui F Ribeiro 的答案完全是关于金钱的,但是,我需要更多的研究才能让一切正常运转,包括次要的东西、变量等等。
为了让在这里看到这个问题的人感兴趣,我发布了解决原始问题用例的脚本,不是因为它是一个替代方案,而是因为它是 Rui F Ribeiro 知识共享的“扩展”。
#!/usr/bin/expect -f
set vpn_url "vpn.domain.com"
set vpn_username "theuser"
set vpn_password "thepassword"
set ubuntu_username "theubuntuloginuser"
set ubuntu_password "theubuntuloginpass"
set force_conservative 0 ;# set to 1 to force conservative mode even if
;# script wasn't run conservatively originally
if {$force_conservative} {
set send_slow {1 .1}
proc send {ignore arg} {
sleep .1
exp_send -s -- $arg
}
}
set timeout -1
spawn $env(SHELL)
match_max 100000
send -- "sudo LD_LIBRARY_PATH=\"/usr/local/lib\" openconnect --juniper --no-cert-check $vpn_url -u $vpn_username\r"
expect {
"password for $ubuntu_username:" {
send -- "$ubuntu_password\r"
}
}
expect -exact "password:"
send -- "$vpn_password\r"
expect eof