问题描述
我一直在尝试编写一个 expect 脚本,该脚本具有打开 ssh 连接的一种方法,并且该方法可以由其他方法调用,以便它们可以发送额外的执行命令。我已经拥有的是 -
#!/usr/bin/expect
set timeout -1
#log_user 0
set username [lindex ${argv} 0]
set node_address [lindex ${argv} 1]
set password [lindex ${argv} 2]
set prompt ".*\[>#:$%\] \?\$"
set password_prompt ".*: \?\$"
set install_dir "/usr/share/elasticsearch"
set conf_dir "/etc/elasticsearch"
set plugin_manager "${install_dir}/bin/elasticsearch-plugin"
set es_config_file "${conf_dir}/elasticsearch.yml"
puts "Attempting login to ${node_address}"
spawn ssh ${username}@${node_address}
expect -re ${password_prompt} {send -- "${password}\n"}
expect -re ${prompt} {send -- "sudo su - kompuser\n"}
expect -re ${prompt}
puts "Logged in to the node ${node_address} successfully"}
expect -re ${prompt}
send -- "curl -XGET 'localhost:9200/_cat/nodes?v&h=ip,node.role'\n"
expect -re ${prompt}
send_user $expect_out(buffer)
我有其他脚本尝试使用类似的代码登录主机,并且有很多代码重复。我想通过编写单个方法来避免代码重复,让我们称之为 login
并在向远程服务器发送任何命令之前调用它,我想要的是 -
#!/usr/bin/expect
set timeout -1
#log_user 0
set username [lindex ${argv} 0]
set node_address [lindex ${argv} 1]
set password [lindex ${argv} 2]
set prompt ".*\[>#:$%\] \?\$"
set password_prompt ".*: \?\$"
set install_dir "/usr/share/elasticsearch"
set conf_dir "/etc/elasticsearch"
set plugin_manager "${install_dir}/bin/elasticsearch-plugin"
set es_config_file "${conf_dir}/elasticsearch.yml"
proc login {username node_address password prompt password_prompt} {
puts "Attempting login to ${node_address}"
spawn ssh ${username}@${node_address}
expect -re ${password_prompt} {send -- "${password}\n"}
expect -re ${prompt} {send -- "sudo su - kompuser\n"}
puts "Logged in to the node ${node_address} successfully"}
proc get_node_info {username node_address password prompt password_prompt} {
login ${username} ${node_address} ${password} ${prompt} ${password_prompt}
expect -re ${prompt}
send -- "curl -XGET 'localhost:9200/_cat/nodes?v&h=ip,node.role'\n"
expect -re ${prompt}}
proc restart_node {username node_address password prompt password_prompt} {
login ${username} ${node_address} ${password} ${prompt} ${password_prompt}
expect -re ${prompt} {send -- "sudo systemctl daemon-reload\n"}
expect -re ${prompt} {send -- "sudo systemctl start elasticsearch.service\n"}
expect -re ${prompt}
}
get_node_info ${username} ${node_address} ${password} ${prompt} ${password_prompt}
restart_node ${username} ${node_address} ${password} ${prompt} ${password_prompt}
问题是调用 login 成功登录但期望调用者中的提示挂起 - 以下是启用调试日志的最后几行日志 -
send: sending "sudo su - kompuser\n" to { exp4 }
Logged in to the node 10.109.14.73 successfully
Gate keeper glob pattern for '.*[>#:$%] ?$' is ''. Not usable,disabling the performance booster.
expect: does "" (spawn_id exp0) match regular expression ".*[>#:$%] ?$"? (No Gate,RE only) gate=yes re=no
任何帮助将不胜感激。 谢谢
解决方法
当您在 proc 内运行 spawn
时,变量 spawn_id
在当前堆栈帧中创建,使其成为局部变量,除非采取特殊措施。
有了这些知识,解决方案很简单:在运行 spawn_id
命令之前将 spawn
声明为全局:
proc login {username node_address password prompt password_prompt} {
global spawn_id
puts "Attempting login to ${node_address}"
spawn ssh ${username}@${node_address}
expect -re ${password_prompt} {send -- "${password}\n"}
expect -re ${prompt} {send -- "sudo su - kompuser\n"}
puts "Logged in to the node ${node_address} successfully"
}
我相信你不需要在其他过程中这样做。但为了一致性,我会。