Expect 脚本:创建使用 ssh 登录远程服务器的方法,并在方法返回后发送命令

Expect script: Create method to login to a remote server using ssh and send commands after method has returned

我一直在尝试编写一个 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}

问题是对登录的调用成功登录,但期待调用者的提示挂起 - 以下是启用调试日志的日志的最后几行 -

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

任何帮助将不胜感激。 谢谢

当您 运行 spawn 在 proc 中时,变量 spawn_id 在当前堆栈帧中创建,除非采取特殊措施,否则使其成为局部变量。

有了这些知识,解决方案就很简单了:在 运行 执行 spawn 命令之前将 spawn_id 声明为全局变量:

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"
}

我相信你不需要在其他过程中这样做。但为了保持一致性,我会。