0

I have written below Shell script which is intended to get Model name from remote host by doing SSH and executing the command.

#!/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

When I execute below command manually, then it gives expected model name as output.

Command: 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

But when its put into script like above it doesn't produce any output.

Also, there are MOTD (Message of the day) configured on most of the servers and "The authenticity of host..." message to adding server into .ssh/known_hosts, So I tried to handle them in script but Expect is failing to handle the situation when MOTD doesn't appear or when remote is already present in .ssh/known_hosts.

Any help is highly appreciated to get this script running.

Expected output:

IP,Model Name
8.8.8.8,C9407R
8.8.8.1,C9407R
8.8.8.2,C9407R
8.8.8.3,C9407R
8
  • Don't ever store password in plaintext in your script. Just configure ssh with ssh-copy-id and run ssh normally. to adding server into .ssh/known_hosts - just don't check it with -o StrictHostKeyChecking=false. Please read bashfaq How can I store the return value and/or output of a command in a variable? Commented Aug 8, 2019 at 10:04
  • @KamilCuk, I know that. But this is a secured private network so, need not to worry about security. Commented Aug 8, 2019 at 10:06
  • @KamilCuk, Also, SSH Key can't be added to all remote host as these are all banking network devices, therefore I have to use passwords only. Commented Aug 8, 2019 at 10:12
  • If you can write to the filesystem, then you can install something. Since you are creating the file 'output.csv', you can write to the filesystem. So you can install things. Commented Aug 8, 2019 at 13:26
  • Is there a typo in the question, or are you really running model=expect -c 'spawn ssh us...? Commented Aug 8, 2019 at 13:27

1 Answer 1

2

First, you're missing the Command Substitution syntax to execute the expect code:

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

Next, to optionally expect patterns, you need the expect {patt1 action1 patt2 action2 ...} form:

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

That way, expect can match any of the patterns. The exp_continue command "loops" within the same expect command so you can match more than one of them. The eof pattern matches when ssh connection closes after the "show version ..." command has finished.

Newlines for readability.

Putting this together:

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
)

I have a feeling that there's more you need to do in the grep part, but you didn't show the output of just the expect command.


update:

  1. use spawn -noecho ssh ... so expect will not print the spawn command.
  2. then, you'll get whatever output ssh needs to show for the login process, and then the "show" command output:
    • if you're expecting exactly 1 line of output, you might want to change grep to tail -n 1.
    • otherwise, show the output you get and we can help you filter out the noise.

update 2: filtering out the noise

I'm going to assume that the regex pattern cisco (.*) processor is what you need to match:

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 turns off the spawned process's ability to write to stdout. Expect can still capture its output though.

Sign up to request clarification or add additional context in comments.

2 Comments

It's not working for: cisco Nexus9000 C9336C-FX2 Chassis
I changed regex and last line like this: -re "cisco (.*) " {puts $expect_out(0,string)}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.