【问题标题】:How to return from shell 'read' command passed in expect script?如何从期望脚本中传递的 shell 'read' 命令返回?
【发布时间】:2015-07-26 11:58:29
【问题描述】:

我对使用 expect 真的很陌生,对于将命令传递给 expect 脚本有点困惑,所以请多多包涵……我搜索了许多论坛,但似乎找不到使用 expect 脚本的示例获取用户输入的读取命令。

在我的 Korn shell 脚本中,我调用了一个期望脚本 (expectssh.exp) 来 ssh 登录到另一台主机,并获取有关该主机的网络配置(网络接口卡号和子网掩码信息)的用户输入。我将四个参数传递给期望脚本:远程主机 IP 地址、用户名、密码和要运行的命令列表。我的期望脚本如下:

#!/usr/bin/expect
# Usage: expectssh <host> <ssh user> <ssh password> <script>

set timeout 60
set prompt "(%|#|\\$) $"
set commands [lindex $argv 3];

spawn ssh [lindex $argv 1]@[lindex $argv 0]

expect {
"*assword:" { 
send -- "[lindex $argv 2]\r" 
expect -re "$prompt"
send -- "$commands\r" 
}

"you sure you want to continue connecting" {
send -- "yes\r"
expect "*assword:"
send -- "[lindex $argv 2]\r"
expect -re "$prompt"
send -- "$commands\r" 
}

timeout {
exit }
}

脚本运行良好,除了当它到达'read'命令时,脚本在用户按下回车后不会继续或退出。它只是挂起。

我传递给期望脚本及其调用的命令如下:

SCRIPT='hostname > response.txt;netstat -rn;read net_card?"What is the network interface card number?   " >> response.txt; read net_mask?"What is the subnet mask? " >> response.txt'

/usr/bin/expect ./expectssh.exp $hostip $usr $pswd "$SCRIPT"

关于如何在不挂起的情况下通过期望脚本传递读取命令的任何建议?

附带说明,因为我知道它会出现 - 我不允许进行基于密钥的自动 SSH 登录。我必须提示输入用户名和密码,这是通过调用这个期望脚本的 Korn shell 脚本完成的。

感谢您提供的任何建议和帮助!

【问题讨论】:

  • 我建议不要远程运行read。如果绝对必须,您可以让您的 TCL 代码在本地提示用户(在运行远程 netstat 之后)。但是,如果您只是使用read 让用户从远程命令中解析内容,而不是让机器自己做……好吧,呃,为什么?!
  • 我不确定我是否理解如何在本地读取这些值。我不知道我正在使用的主机是否在同一个子网上,所以这是我在继续安装之前试图确定的内容(以及用于设置虚拟 IP 的网络接口卡信息)。我只有远程主机的 IP 地址。有没有办法自动获取该主机的网络接口卡号和子网掩码而无需询问用户?
  • "我只有远程主机的IP地址。有没有办法自动获取该主机的网络接口卡号和子网掩码而无需询问用户?" - 是的;由于您可以通过 SSH 登录该机器,因此您确实可以解析出来。你为什么不把它当作自己的问题来问呢? (请务必在该问题中提供目标主机的操作系统,并随时在此处链接)。
  • 谢谢!正如你所建议的,我发布了这个问题。 stackoverflow.com/questions/30246952/…

标签: linux shell ssh user-input expect


【解决方案1】:

对于任何感兴趣的人,我可以通过做一些事情让read 命令为用户输入工作:

(1) 将其放在-re $prompt 块中,而不是在密码输入后附加send -- "$commands\r"

(2) 将命令硬编码到脚本中,而不是将它们传递进去。

(3) 在命令后面加上interact 语句,这样在用户响应之前不会输入下一个发送命令。

我的期望块现在看起来像这样:

expect {
    -re "(.*)assword:" { 
        send -s "$pswd\r" 
        exp_continue
    }
    "denied, please try again" {
        send_user "Invalid password or account.\n"
        exit 5
    }
    "incorrect" {
        send_user "Invalid password or account.\n"
        exit 5
    }
    "you sure you want to continue connecting" {
        send -s "yes\r"
        exp_continue
    }
    -re $prompt {
        set timeout -1
        send -- "hostname > partnerinit\r"
        expect -exact "hostname > partnerinit\r"
        send -s "netstat -rn\r"
        expect -re "$prompt"
        send -- "read n_card?'Enter the network interface card number for this server (i.e. eth0):  '\r"
        interact "\r" return
        send -- "\r"
        send -- "echo \$n_card >> partnerinit\r"
        send -- "msk=\$(cat /etc/sysconfig/network-scripts/ifcfg-\$n_card | grep NETMASK)\r"
        send -- "msk=\$(echo \${msk#NETMASK=})\r"
        send -- "echo \$msk >> partnerinit\r"
        send -- "cat partnerinit\r"
        set retval 0
    }
    timeout {
        send_user "Connection to host $host timed out.\n"
        exit 10
    }
    eof {
        send_user "Connection to host $host failed.\n"
        exit 1
    }
}

我还更新了脚本以根据用户输入的网络接口卡号自动确定子网掩码。引起我注意的是,在具有多个接口卡的盒子的情况下,很难自动查找网络接口卡号。最好从小处着手,让用户输入它,然后在整个脚本正常工作后对其进行微调/自动化。

现在我正在修改它以将我的 partnerinit 文件 scp 回我的本地主机,并从每个预期条件返回有意义的退出状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 2022-01-23
    • 1970-01-01
    • 2022-07-12
    • 1970-01-01
    • 2013-04-19
    • 2014-12-16
    • 1970-01-01
    相关资源
    最近更新 更多