如何在 Shell 脚本中像嵌套 If Else 循环一样使用 expect?

How to use expect in Shell script like nested If Else loop?

我在下面编写了 Shell 脚本,旨在通过执行 SSH 并执行命令从远程主机获取模型名称。

#!/bin/bash

> output.csv

IFS=","

echo "IP,Model Name" >> output.csv

while read ip
do
    #echo "Current IP is: $ip"      

    model=expect -c 'spawn ssh username@'"$ip"' "show version | in cisco"; expect -re "The.*(yes/no)?"; send "yes\r";  expect -re ".*UNAUTH.*password:"; send "password\r";' | grep cisco

    echo "$ip,$model" >> output.csv

done < Check_SSH.csv

当我手动执行以下命令时,它会给出预期的模型名称作为输出。

命令: expect -c 'spawn ssh username@'"$ip"' "show version | in cisco"; expect -re "The.*(yes/no)?"; send "yes\r"; expect -re ".*UNAUTH.*password:"; send "password\r";' | grep cisco

但是当它像上面那样放入脚本时它不会产生任何输出。

此外,大多数服务器上都配置了 MOTD(每日消息)和“主机的真实性...”将服务器添加到 [=14] 中的消息=], 所以我尝试在脚本中处理它们,但是当 MOTD 没有出现或者远程已经存在于 .ssh/known_hosts.

中时,Expect 无法处理这种情况

非常感谢获得此脚本的任何帮助 运行。

预期输出:

IP,Model Name
8.8.8.8,C9407R
8.8.8.1,C9407R
8.8.8.2,C9407R
8.8.8.3,C9407R

首先,您缺少执行预期代码的 Command Substitution 语法:

model=$(expect -c ...)
# ....^^.............^

接下来,要可选地期望模式,您需要expect {patt1 action1 patt2 action2 ...}形式:

expect -c '
    spawn ssh username@'"$ip"' "show version | in cisco"
    expect {
        -re "The.*(yes/no)?"      {send "yes\r"; exp_continue}
        -re ".*UNAUTH.*password:" {send "password\r"; exp_continue}
        eof
    }
'

这样,expect 可以匹配任何 模式。 exp_continue 命令 "loops" 在同一 expect 命令中,因此您可以匹配多个命令。当 "show version ..." 命令完成后 ssh 连接关闭时,eof 模式匹配。

换行以提高可读性。

放在一起:

model=$(
    expect -c '
        spawn ssh username@'"$ip"' "show version | in cisco"
        expect {
            -re "The.*(yes/no)?"      {send "yes\r"; exp_continue}
            -re ".*UNAUTH.*password:" {send "password\r"; exp_continue}
            eof
        }
    ' | grep -i cisco
)

我感觉您在 grep 部分还需要做更多的事情,但是您没有显示 expect 命令的输出。


更新:

  1. 使用 spawn -noecho ssh ... 所以 expect 不会打印 spawn 命令。
  2. 然后,您将获得 ssh 需要为登录过程显示的任何输出,然后是 "show" 命令输出:
    • 如果您只需要 1 行输出,您可能需要将 grep 更改为 tail -n 1
    • 否则,请显示您获得的输出,我们可以帮助您过滤掉噪音。

更新 2:滤除噪音

我假设正则表达式模式 cisco (.*) processor 是您需要匹配的:

model=$(
    expect -c '
        log_user 0
        spawn ssh username@'"$ip"' "show version | in cisco"
        expect {
            -re "The.*(yes/no)?"       {send "yes\r"; exp_continue}
            -re ".*UNAUTH.*password:"  {send "password\r"; exp_continue}
            -re "cisco (.*) processor" {puts $expect_out(1,string)}
        }
        expect eof
    '
)

log_user 0 关闭派生进程写入标准输出的能力。 Expect 仍然可以捕获它的输出。