How to have expect timeout when trying to login to an ssh session it has spawned?
First of all I would use an expect script for this and lose the bash scripting.
Then for the expect part: You can do this by using a switch that also matches for timeout (page 12 of exploring expect). In that way you can explicitly have some action when expect timeouts.
Otherwise by setting the timeout it will just continue with the next command in line.
set timeout 60
expect {
"assword:" {
}
timeout {
exit 1 # to exit the expect part of the script
}
}
I've created something similar where I used an overall expect script to run an expect script in parallel.
multiple.exp
#!/bin/sh
# the next line restarts using tclsh \
exec expect "$0" "$@"
# multiple.exp --
#
# This file implements the running of multiple expect scripts in parallel.
# It has some settings that can be found in multiple.config
#
# Copyright (c) 2008
#
# Author: Sander van Knippenberg
#####
# Setting the variables
##
source [file dirname $argv0]/.multiple.config
# To determine how long the script runs
set timingInfo("MultipleProcesses") [clock seconds]
# ---------------------------------------------------------------------
######
# Procedure to open a file with a certain filename and retrieve the contents as a string
#
# Input: filename
# Output/Returns: content of the file
##
proc openFile {fileName} {
if {[file exists $fileName] } {
set input [open $fileName r]
} else {
puts stderr "fileToList cannot open $fileName"
exit 1
}
set contents [read $input]
close $input
return $contents
}
######
# Procedure to write text to a file with the given filename
#
# Input: string, filename
##
proc toFile {text filename} {
# Open the filename for writing
set fileId [open $filename "w"]
# Send the text to the file.
# Failure to add '-nonewline' will reslt in an extra newline at the end of the file.
puts -nonewline $fileId $text
# Close the file, ensuring the data is written out before continueing with processing
close $fileId
}
# ---------------------------------------------------------------------
# Check for the right argument
if {$argc > 0 } {
set hostfile [lindex $argv 0]
} else {
puts stderr "$argv0 --- usage: $argv0 <hosts file>"
exit 1
}
# Create the commands that can be spawned in parallel
set commands {}
# Open the file with devices
set hosts [split [openFile $hostfile] "\n"]
foreach host $hosts {
if { [string length $host] > 1 } {
lappend commands "$commandDir/$commandName $host" # Here you can enter your own command!
}
}
# Run the processes in parallel
set idlist {}
set runningcount 0
set pattern "This will never match I guess"
# Startup the first round of processes until maxSpawn is reached,
# or the commands list is empty.
while { [llength $idlist] < $maxSpawn && [llength $commands] > 0} {
set command [lindex $commands 0]
eval spawn $command
lappend idlist $spawn_id
set commands [lreplace $commands 0 0]
incr runningcount
set commandInfo($spawn_id) $command
set timingInfo($spawn_id) [clock seconds]
send_user " $commandInfo($spawn_id) - started\n"
}
# Finally start running the processes
while {$runningcount > 0} {
expect {
-i $idlist $pattern {
}
eof {
set endedID $expect_out(spawn_id)
set donepos [lsearch $idlist $endedID]
set idlist [lreplace $idlist $donepos $donepos]
incr runningcount -1
set elapsedTime [clock format [expr [clock seconds] - $timingInfo($endedID)] -format "%M:%S (MM:SS)"]
send_user " $commandInfo($endedID) - finished in: $elapsedTime\n"
# If there are more commands to execute then do it!
if {[llength $commands] > 0} {
set command [lindex $commands 0]
eval spawn $command
lappend idlist $spawn_id
set commands [lreplace $commands 0 0]
incr runningcount
set commandInfo($spawn_id) $command
set timingInfo($spawn_id) [clock seconds]
}
}
timeout {
break
}
}
}
set elapsed_time [clock format [expr [clock seconds] - $timingInfo("MultipleProcesses")] -format "%M:%S (MM:SS)"]
send_user "$argv0 $argc - finished in: $elapsedTime\n"
multiple.config
# The dir from where the commands are executed.
set commandDir "/home/username/scripts/expect/";
set commandName "somecommand.exp";
# The maximum number of simultanious spawned processes.
set maxSpawn 40;
# The maximum timeout in seconds before any of the processes should be finished in minutes
set timeout 20800;
dunxd
I'm currently freelance specialising in international connectivity and infrastructure working with clients in the humanitarian space. If your organisation struggles to work effectively because of limited internet options in far flung locations, maybe I can help. Until 2017 I worked at a large international development charity in London, as International Operations Manager. I managed a team of Regional ICT Service Managers, based in developing world countries, who kept the users happy through fixing problems, setting up great connectivity and generally making sure users could do their day jobs. I think I did a good job as a manager - some of my team went on to great things! I previously worked at the same place as International Network Systems Analyst. I looked after a bunch of ICT systems in offices in the developing world, as well as looking after systems in our HQ. I gained a lot of knowledge in that job, and the techy side competes with the people stuff in the new role, hence I still hang out here a lot. I'm passionate about the use of ICT in developing countries, both in terms of dealing with the inherent problems for ICT in those places, and using ICT as a tool for development.
Updated on December 20, 2020Comments
-
dunxd over 3 years
I am writing an bash script that uses expect to login to a bunch of Cisco ASAs (they don't support certificate login, hence using expect), makes a change to the configuration and then logs out.
I'd like the script to move onto the next ASA if it is unable to login.
Here is the script:
#!/bin/bash # Scriptname: set-mtu for asa in $(cat asa-list-temp) do /usr/bin/expect << EndExpect spawn ssh admin_15@$asa expect "assword:" send "pa$$w0rd\r" expect ">" send "do something\r" expect ">" send "exit\r" EndExpect done
I think I can set a timeout on
expect "assword:"
but I can't figure out how to get it to close the spawned ssh session and then move onto the next ASA in the for list. -
dunxd almost 13 yearsKind of helpful, but I don't own Exploring Expect, and I don't really want to rewrite my short script into a much longer one in a language I don't yet know.
-
Sander van Knippenberg almost 13 yearsThe first bit will do what you request. The second bit is a hint as to how you can optimize what you want to do using expect. Exploring expect can be found here: my.safaribooksonline.com/9781565920903/…