minorix
minorix

Reputation: 71

Bash/Expect Script for SSH

I am new to Expect and scripting in general. I am trying to make a few scripts to make my life a bit easier when pulling network device configurations. I managed to create a basic Expect script to SSH to a device and save the configuration.

I want to expand upon this and allow the script to connect to a number of IP addresses instead of just one like I have right now. I have a file named list.txt with a few different IP addresses with each IP address on a separate line.

What would I need to do to have the Expect script connect to each of these IP addresses and perform the rest of the tasks in the script as well?

Here is the Expect script I have so far:

#!/usr/bin/expect -f
# Tells interpreter where the expect program is located.  This may need adjusting according to
# your specific environment.  Type ' which expect ' (without quotes) at a command prompt
# to find where it is located on your system and adjust the following line accordingly.
#
#
# Use the built in telnet program to connect to an IP and port number
spawn ssh 192.168.1.4 -l admin
#
# The first thing we should see is a User Name prompt
#expect "login as:"
#
# Send a valid username to the device
#send "admin"
#
# The next thing we should see is a Password prompt
expect "Password:"
#
# Send a valid password to the device
send "password\n"
#
# If the device automatically assigns us to a privileged level after successful logon,
# then we should be at an enable prompt
expect "Last login:"
#
# Tell the device to turn off paging
#
# After each command issued at the enable prompt, we expect the enable prompt again to tell us the
# command has executed and is ready for another command
expect "admin@"
#
# Turn off the paging
send "set cli pager off\n"
#
# Show us the running configuration on the screen
send "show config running\n"
#
# Set the date.
set date [timestamp -format %C%y%m%d]
#
# Test output sent to file with a timestamp on end
#-noappend will create a new file if one already exists
log_file -noappend /home/test.cfg$date
#
expect "admin@"
#
# Exit out of the network device
send "exit\n"
#
# The interact command is part of the expect script, which tells the script to hand off control to the user.
# This will allow you to continue to stay in the device for issuing future commands, instead of just closing
# the session after finishing running all the commands.`enter code here`
interact

Do I need to integrate this with a Bash script? If so, is it possible to read one line of the list.txt file, use that as the IP address/host variable and then read the next and repeat?

Upvotes: 7

Views: 58773

Answers (5)

Peter Marsh
Peter Marsh

Reputation: 1

Here's a good way to integrate expect with bash:

ssh_util.expect-

#!/usr/bin/expect

set timeout -1
set ip   [lindex $argv 0]
set user [lindex $argv 1]
set pwd  [lindex $argv 2]
set commands [lrange $argv 3 [llength $argv]]

spawn ssh -o LogLevel=QUIET -t $user@$ip $commands

expect {
    yes/no       {send "yes\r" ; exp_continue}
    *?assword    {send "$pwd\r" ; exp_continue}
}

You can run this in the terminal with ./ssh_util.expect <commands...>. In your shell script you can use it to run commands on your host machine like this:

example.sh -

#! /bin/bash

# ssh_exp <commands...>
ssh_exp () {
    ./ssh_util.expect 192.168.1.4 username password $*
}

# run commands on host machine here
ssh_exp ls
ssh_exp ls -la
ssh_exp echo "Echo from host machine"

# you can even run sudo commands (if sudo password is same as user password)
ssh_exp sudo apt install 

Make sure to run

chmod +x ssh_util.expect
chmod +x example.sh

in the terminal to make both files executable. Hope this helps!

Upvotes: 0

abcdefgh
abcdefgh

Reputation: 83

Or use set ip [gets stdin] to the IP address from the user input.

For example,

puts "Enter your IP address\n"
set ip [get stdin]

Use this in spawn. We can do the same for multiple IP addresses using a loop -

spawn ssh $ip -l admin

Upvotes: 0

andrade
andrade

Reputation: 156

A possibility is to pass the IP address as a parameter in your Expect script:

set host_ip [lindex $argv 0]

and then make a shell script, calling your Expect script inside a while loop:

ips_file="list.txt"

while read line
do
    your_expect_script line
done < $ips_file

Upvotes: 1

jmrenouard
jmrenouard

Reputation: 104

This is a Perl version for this issue:

Install instruction:

cpan Expect

This script works perfectly for my needs.

Parameter 1: Connection string (example: [email protected])
Parameter 2: Clear text password
Parameter 3: Command to execute

#!/usr/bin/perl
use strict;

use Expect;

my $timeout = 1;

my $command = "ssh " . $ARGV[0] . " " . $ARGV[2];

#print " => $command\n";

my $exp = Expect->spawn($command) or die "Cannot spawn $command: $!\n";
$exp->raw_pty(1);

LOGIN:
$exp->expect($timeout,
        [ 'ogin: $' => sub {
                     $exp->send("luser\n");
                     exp_continue;
                }
        ],
        [ 'yes\/no\)\?\s*$' => sub {
                    $exp->send("yes\n");
                    goto LOGIN;
                }
        ],
        [ 'assword:\s*$' => sub {
                    $exp->send($ARGV[1]."\n");
                    #print "password send: ", $ARGV[1];
                    exp_continue;
                }
        ],
        '-re', qr'[#>:] $'
);
$exp->soft_close();

Upvotes: 2

glenn jackman
glenn jackman

Reputation: 246774

I would do this (untested):

#!/usr/bin/expect -f

set logfile "/home/text.cfg[clock format [clock seconds] -format %Y%m%d]"
close [open $logfile w]         ;# truncate the logfile if it exists

set ip_file "list.txt"
set fid [open $ip_file r]

while {[gets $fid ip] != -1} {

    spawn ssh $ip -l admin
    expect "Password:"
    send "password\r"

    expect "admin@"
    send "set cli pager off\r"

    log_file $logfile
    send "show config running\r"

    expect "admin@"
    log_file 

    send "exit\r"
    expect eof

}
close $fid

Notes:

  • I removed all your comments for brevity
  • use \r to simulate hitting enter when you send commands.
  • I assumed you only want to log the "show config running" output
  • use expect eof after you send "exit"

Upvotes: 3

Related Questions