user1902689
user1902689

Reputation: 1775

Why doesn't this expect handle timeout or eof

Why does this expect script continually spawn the ssh command, never printing "going to sleep" or "out of sleep", and never sleeping?

My intention is to try ssh'ing, if it sees "password: " to exit the while loop (more code not seen here would include an interact.) If 3 seconds go by, or ssh dies before then, it should puts, sleep for 3 seconds, puts again, and try ssh again.

The hostname "doesntexist" is used to force a failure, such as Name or service not known.

#!/usr/bin/expect -f

set readyForPassword 0
while { $readyForPassword == 0 } {
   spawn ssh nouser@doesntexist
   expect -timeout 3 {
      "password: " {
         set readyForPassword 1
      } timeout {
         puts "going to sleep"
         sleep 3
         puts "out of sleep"
      } eof {
         puts "going to sleep"
         sleep 3
         puts "out of sleep"
      }
   }
}

Upvotes: 2

Views: 3537

Answers (1)

Dinesh
Dinesh

Reputation: 16428

When -timeout flag is used, it should be prior to the Expect's pattern, not on the actions.

By debugging, we can find that the pattern being taken by Expect with your existing code is,

expect: does "" (spawn_id exp6) match glob pattern "\n      "password: " {\n         set readyForPassword 1\n      } timeout {\n         puts "going to sleep"\n         sleep 3\n         puts "out of sleep"\n      } eof {\n         puts "going to sleep"\n         sleep 3\n         puts "out of sleep"\n      }\n   "? no

From the 76th page of the Exploring Expect book, we can see the below statements,

The initial open brace causes Tcl to continue scanning additional lines to complete the command. Once the matching brace is found, all of the patterns and actions between the outer braces are passed to expect as arguments

What went wrong then ?

The -timeout is not an action, but just a flag. Expect assumed the following as the pattern

"password: " {
         set readyForPassword 1
      } timeout {
         puts "going to sleep"
         sleep 3
         puts "out of sleep"
      } eof {
         puts "going to sleep"
         sleep 3
         puts "out of sleep"
      }

Remember, Expect does not mandate the action, only the pattern i.e. It will act as if we like only pattern is given, but no action to be taken.

Simply put, you code is as equivalent as

expect "Hello"; # Either 'timeout' or pattern can be matched. But, no action at all 

Your code should be re-arranged as,

#!/usr/bin/expect -d
set readyForPassword 0
while { $readyForPassword == 0 } {
   spawn ssh nouser@doesntexist
   expect {
        -timeout 3 "password: " {set readyForPassword 1}
        timeout {
                puts "going to sleep in timeout"
                sleep 3
                puts "out of sleep in timeout"
        } eof {
                puts "going to sleep in eof"
                sleep 3
                puts "out of sleep in eof"
        }
   }
}

Upvotes: 4

Related Questions