Tcl / expect need to attempt telnet if failed ssh

Morning and Happy New Year to all.

I am in a situation where I need to connect to a list of devices that are using either telnet or ssh.
I want to try to telnet, if I receive any of the following I want to attempt ssh :

"Connection refused"
"Connection timed out"
timeout expiration

#!/usr/bin/expect -d
set dev [lindex $argv 0]
set hnam [lindex $argv 1]
set timeout 10
set unam [lindex $argv 2]
set password [lindex $argv 3]
spawn telnet $dev
      expect {
             "sername" { send "$unam\n"; }
             "login"   { send "$unam\n"; }
#             -re "Connection refused|Connection timed out" { spawn ssh -o StrictHostKeyChecking=no $dev -l $unam }
             timeout { spawn ssh -o StrictHostKeyChecking=no $dev -l $unam
                     expect {
                            timeout { set err [ open "$hnam\_$dev.err" w ] ;
                                      puts $err "SSH timed out for $dev.\n";
                                      log_file ;
                                      exit; }

                             }

                     }
             }
sleep 1
            expect "assword"       { send "$password\n"; }
            expect -re {[#>] ?$}    { send "show clock\n" }
            expect -re {[#>] ?$}    { send "exit\n" }
wait
close $spawn_id

So my question is .. how do I use "|" or "OR" in tcl/expect I have been searching the web but havent found a good example.

Some Psuedo

spawn a telnet session
if Connection refused or Connection timed out or the time out expires
spawn a ssh session
.
.
.
.
end

Thanks in advance ..

I haven't tried what you're trying to do before, but the syntax you're using mostly looks OK.

You haven't said what operating system you're using and that can make a difference for some versions of ssh . On most systems, the destination device has to follow the options, so there is a chance that it might work if you change:

#             -re "Connection refused|Connection timed out" { spawn ssh -o StrictHostKeyChecking=no $dev -l $unam }
             timeout { spawn ssh -o StrictHostKeyChecking=no $dev -l $unam
                     expect {
                            timeout { set err [ open "$hnam\_$dev.err" w ] ;
                                      puts $err "SSH timed out for $dev.\n";
                                      log_file ;
                                      exit; }

                             }

                     }
             }

to:

             -re "Connection refused|Connection timed out" {
                     spawn ssh -o StrictHostKeyChecking=no -l $unam $dev
                     expect {
                            timeout { 
                                      set err [ open "$hnam\_$dev.err" w ] ;
                                      puts $err "SSH timed out for $dev.\n";
                                      log_file ;
                                      exit;
                            }
                    }
             }
             timeout { spawn ssh -o StrictHostKeyChecking=no -l $unam $dev
                     expect {
                            timeout { set err [ open "$hnam\_$dev.err" w ] ;
                                      puts $err "SSH timed out for $dev.\n";
                                      log_file ;
                                      exit; }
                             }
                     }
             }

Obviously, this is totally untested. I would suggest that you turn on tcl 's debugging output by including the -d option when you start it.

1 Like

Thanks fellas .. Centos linux .. and I am using the -d .. but that doesnt give me much info related to using an "OR"

Maybe I'm not understanding your question.

The script you showed us in post #1 in this thread invokes expect four times. The first invocation has three conditions and corresponding actions to be performed if any one of those three conditions are met. That is a classical logical OR operation. The first two conditions in that expect are literal string matches and the last is a timeout condition. You also have a commented out regular expression match that would match either of two other literal strings separated by a vertical bar symbol ( | ) that also acts as a logical OR when matching either of the literal strings Conection refused and Connection timed out and gives an action that is to be performed if either of those literal strings are matched.

Note that the first two patterns and actions in the first invocation of expect have identical actions (i.e. { send "$unam\n"; } ) so the two patterns and actions:

             "sername" { send "$unam\n"; }
             "login"   { send "$unam\n"; }

should be able to be replaced by:

             -re "sername|login" { send "$unam\n"; }

and get the same results.

The action in the commented out regular expression match seemed to be incomplete because it didn't include the additional steps in the action that were present in the timeout condition's action after spawning ssh . Each action for a pattern has to be complete; actions for one pattern are never used when another pattern is matched.

Unfortunately, there is no regular expression that can look for various strings AND look for the timeout condition. So, you have to duplicate the actions that you have for the timeout condition as the actions to be performed for the regular expression match of the two strings.

Since there is no opening brace ( { ) between the expect and the pattern for the last threee invocations of expect in your script, there can only be one pattern and action for each of those invocations of expect . The first invocation of expect in your script has braces surrounding the three patterns (and the comment that will be ignored) that will be acted upon whenever the first, second, OR third pattern is matched in the input that expect is reading.

Does this cover what you're trying to do?