Alright, You said you were new to expect so please don't be frightened off by this. Others have different ways of doing things. If you need help with the program, please feel free to ask.
You will need to give me regexp matches in the login
sequence for ssh most probably.
\\<start\\>
#!/usr/bin/expect
####BUILTIN DEBUGGING##############
#uncomment the line below for detailed debugging feedback
#exp_internal 1
####################################
########settings for program#####
array set allInfo {
spawnids ""
logfile "tmp.txt"
ider "uname -a ; whoami"
direc "/home"
debug 0
prompt ".*@.*"
timeout "1000"
}
####set allInfo(debug) to 1 for a constant trace against interact.#########
if {$allInfo(debug) > 0} {
trace variable interact_out w [list AlertMe]
}
set timeout $allInfo(timeout)
################procedures####################
#logging procedure, writes to file specified in allInfo(logfile)
proc Elogger {linfo} {
global allInfo
if {![catch {set fd [open $allInfo(logfile) "a+"]}]} {
puts $fd "$linfo\n"
catch {flush $fd}
close $fd
}
return
}
#reads all id's in allInfo(spawnids) and compares them prompting you to change
#if you'd like to another login host
proc switch_host {id} {
global allInfo
foreach cid $allInfo(spawnids) {
send_user "Current id = $id\n"
send_user "Switch to $cid (?) \[y/n\] :"
set ans [gets stdin]
if {"$ans" == "y" || "$ans" == "Y"} {
concentrator $cid
}
}
return
}
#main procedure ::takes care of the interacting..
#think of it as a traffic cop

proc concentrator {id {cmd ""}} {
global user_spawn_id allInfo interact_out
set spawn_id $id
if {[info exists cmd] && [string length $cmd] > 1} {
send "$cmd\r"
expect -re "$allInfo(prompt)" {
send_user "$expect_out(buffer)\n"
}
}
usage
send "$allInfo(ider)\r"
interact {
"~SWTH" {switch_host $spawn_id ; Elogger "Changed to $spawn_id"}
"~CDIR" {send_all_ids "cd $allInfo(direc)\r"}
"~LOGV" {send_all_ids "tail -n100 /var/log/messages\r"}
"~CMD" {send_user "Command to send to all hosts: " ; set mcmd [gets stdin] ; send_all_ids "$mcmd\r"}
"~QUIT" {send_all_ids "exit\r" ; catch {send_user "[parray interact_out]\n"} ; Elogger "Disconnect at [clock format [clock seconds]]" ; exit}
"~USE" {usage}
}
-o
timeout 200 {
send_all_ids "\r\n"
send_user "Sent keepalive to all hosts"
}
}
#if allInfo(debug) is set > 0 this trace will become active against all writes to interact_out.
proc AlertMe {x y z} {
global interact_out
catch {send_user "Caught new write event to array interact_out: [parray interact_out]\n"}
return
}
#a usage blurb, lets you know whats going on and how to do it.
proc usage {} {
global user_spawn_id
send -i $user_spawn_id "Usage for [info script]. Once connected you may issue any of the following commands:\n ~SWTH: Switches you to an individual host \n ~CDIR: sends all hosts the command cd to the configured directory in the array allInfo \n ~LOGV: sends all hosts the command as tail -n100 /var/log/messages \n ~CMD: prompts user for command to send to all connected hosts \n ~QUIT: sends all hosts exit and then does some final checks. \n ~USE: reprints this usage message \n \r\n\n"
}
#sends $cmd to all id's in $allInfo(spawnids)
proc send_all_ids {cmd} {
global allInfo
foreach id $allInfo(spawnids) {
send -i $id "$cmd\r"
expect -i $id -re $allInfo(prompt) {
send_user "Read $expect_out(buffer)\n"
catch {Elogger $expect_out(buffer)}
}
}
return
}
########end procedures#################################
#################MAIN()#################################
##for the main portion we read from the number of args to #the script(each a hostname) and connect to these recording #their id's in our idlist
#we should probably handle the login initially one at a #time so that we can handle errors then we'll interact with #the first id##########
if {[llength $argv]} {
for {set i -1} {$i <= [llength $argv]} {incr i} {
if {[string length [lindex $argv $i]]} {
spawn ssh myname@[lindex $argv $i] ;# you need to #replace this with a valid ssh loginstring
lappend allInfo(spawnids) $spawn_id
send_user "Connecting to: [lindex $argv $i]\n"
expect {
-re "Pass.*" { ;# you need to replace this #prompt with the password prompt sent by your ssh #machines.####################
send_user "Password for [lindex $argv $i]"
set pass [gets stdin]
send "$pass\r"
expect -re "$allInfo(prompt)" {
send "\rTERM=vt100\r"
}
}
}
}
}
} else {
error "You must specify at least one host to connect to"
} ;#all done
####now connect to the first of the hosts,and start #stuff####################
puts "$allInfo(spawnids) , idlist"
concentrator [lindex $allInfo(spawnids) 0] $allInfo(ider)
\\<end\\>
This has been tested with a login program and works well.
Not the prettiest thing, but usable.