expect: timeout for pattern action block only?

mlnpscda
mlnpscda used Ask the Experts™
on
Is there a way to set a timeout for just a pattern action block independent of (or maybe subordinate to) the global timeout parameter?

set timeout 15

spawn telnet $target

send "\r"
expect {
      "login:"      { send "$AUTOUSER\r" ; exp_continue }
      "ssword:"        { send "$PASSWORD\r"; exp_continue }
      "$->"            { grab_stats }
      timeout            { send_log -- "GARBAGE OR CANNOT CONNECT\n"; exit }  ## Can the  timeout for this default be set up less than the global timeout set above?
      }


Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Duncan RoeSoftware Developer

Commented:
Yes ... effectively. There is only one timeout variable, but you can change it around a block - that's quite a common thing to do
set saved_timeout $timeout
set timeout 100 ;# Or whatever you want
# Do your block here
set timeout $saved_timeout

Open in new window

Author

Commented:
So, something like:

set timeout 15

spawn telnet $target

send "\r"

set timeout 5
expect {
      "login:"      { send "$AUTOUSER\r" ; exp_continue }
      "ssword:"        { send "$PASSWORD\r"; exp_continue }
      "$->"            { grab_stats }
      default          { send_log -- "GARBAGE OR CANNOT CONNECT\n"; exit }
      }

set timeout 15
Software Developer
Commented:
Sure, that would be fine as far as timeouts go. But it's an unfortunate example - when you spawn telnet you get a login: prompt without sending anything. The extra \r elicits another login: prompt. This might confuse your script. Of course, your target system may be different - worth checking.
Double quotes are only for preserving spaces in strings - strings with any other special characters need braces. Also, rather than do mainline code in the expect loop, I would let it finish and do the code afterwards.
Unlike with shell scripting, you don't have to guard against the possibility that the value of an argument contains spaces (i.e. if the argument name does not contain a space then it does not have to be quoted).
I left the quotes around login: and ssword: to match the following space

set timeout 15

spawn telnet $target

set timeout 5
expect {
      "login: "    {send $AUTOUSER\r; exp_continue}
      "ssword: "       {send $PASSWORD\r; exp_continue}
      {$->}            {}
      default          {send_log -- "GARBAGE OR CANNOT CONNECT\n"; exit }
      }

set timeout 15

# grab_stats

Open in new window

Author

Commented:
this is good.  I'm learning something.  Thanks.

A new question comes to mind, is the 'global timeout' for the whole expect script?  In other words, the whole script has, say, 15 seconds to finish?  or just for expect blocks?

Regarding the procedure in the expect loop, let be be sure I'm understanding the keywords:

exp_continue: continue checking (looping?) inside the expect loop.
{} : exit the expect block and continue with the statements after the expect block (in this case the grab_stats statements)
exit:  exit the whole script and return to the calling shell or program (with a return code of zero or true?)

Can I do an exit <some number> to return exit codes to the calling shell or program?

Thanks again!

Duncan RoeSoftware Developer

Commented:
Your understanding is correct. Yes you can give exit a return code. exit is actually a Tcl command; the man pages for Tcl commands are in section n so you can read about Tcl's exit by entering "man -s n exit" or "man n exit". timeout is a global variable but there is a -timeout option to the expect command to set the timeout for that expect without disturbing the global.

Actually if you set timeout before reading it, you now have a local copy. See this extract from the Expect man page:

"Expect takes a rather liberal view of scoping.  In particular, variables read by commands specific to the Expect program will be sought first from the local scope,
 and  if  not  found,  in  the global  scope.   For  example, this obviates the need to place "global timeout" in every procedure you write that uses expect.  On the other
hand, variables written are always in the local scope (unless a "global" command has been issued).  The most common problem this causes is when spawn is
executed in a procedure.  Outside the procedure, spawn_id no  longer  exists,  so  the  spawned process is no longer accessible simply because of scoping.  Add a
"global spawn_id" to such a procedure."

Author

Commented:
Thanks!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial