Home     |     .Net Programming    |     cSharp Home    |     Sql Server Home    |     Javascript / Client Side Development     |     Ajax Programming

Ruby on Rails Development     |     Perl Programming     |     C Programming Language     |     C++ Programming     |     IT Jobs

Python Programming Language     |     Laptop Suggestions?    |     TCL Scripting     |     Fortran Programming     |     Scheme Programming Language


 
 
Cervo Technologies
The Right Source to Outsource

MS Dynamics CRM 3.0

TCL(Tool Command Language) Scripting

Expect - hangs when called from a nested procedure.


Running Active Tcl 8.4.14 on Windows  XP.

Are there any known issues with Expect when called from a 2 level
nested procedure?  I have an FTP Expect script that hangs when the
calling script is moved to a procedure.

E.G  This works - top level script calls dialog procedure(see below
for dialog proc details.

expectFTP,tcl

    .................
    .................
    set variables
    spawn ftp $host

    set prompt     "(Name|login|Login|Username|User).*:.*"
    set sendString "$user1"

    # call diaglog proc
    dialog $spawn_id $prompt $sendString

    #set prompt     "Password:"
    set sendString "$userpassword1"

    #call dialog proc
    dialog $spawn_id $prompt $sendString

E.G  This fails - top level script calls expectFTP_proc procedure
which calls dialog proc details.  The "spawn" creates the FTP
connection, identifies the "User" prompt and submits the "userid" send
string but then the script hangs on "Password".  The debug output
indicates that there is no response from the "userid" send so the FTP
server waits for the userid while Expects looks for the password
prompt.

This only occurs when the code that calls dialog.proc is moved from
the top level script into a procedure.

I can email the complete script is anyone is interested .

Thanks.

Patrick.

expectFTP,tcl

    .................
    .................
    set variables

    # call expectFTP_proc

    expectFTP_proc

        set variables

        spawn ftp $host

        set prompt     "(Name|login|Login|Username|User).*:.*"
        set sendString "$user1"

        # call diaglog proc
        dialog $spawn_id $prompt $sendString

        #set prompt     "Password:"
        set sendString "$userpassword1"

        #call dialog proc
        dialog $spawn_id $prompt $sendString

==================================================

proc dialog { ftpSpawnId prompt sendString } {

    global ftpErrorMatch

    puts \n
    puts "spawnid         is $ftpSpawnId"
    puts "expected prompt is $prompt"
    puts "sendString      is $sendString"

    exp_log_user 1

    expect {

         -i $ftpSpawnId

         -re $prompt {
                puts "matched on prompt"
                exp_send      "$sendString\r"
                exp_send_user "$sendString\n"
         }

         "Unknown host" {
                puts "ERROR: Unknown host"
                expect *
                error "Expected: '$prompt'. Saw: $expect_out(buffer)"
         }

         $ftpErrorMatch {
                    puts "ERROR: FTP Error"
                    expect *
                    error "Expected: '$prompt'. Saw:
$expect_out(buffer)"
             }

         timeout {
                puts "ERROR: timeout exceeded"
                expect *
                error "Expected: '$prompt'. Saw: $expect_out(buffer)"
         }

         eof {
                expect *
                error "Expected: '$prompt'. Saw: $expect_out(buffer)"
         }
    }

    return [ array get expect_out ]

I turned on the Expect diagnostics which shows how Expect parses the
return prompt.

The problem is that Expect does not parse the return prompt fully.  In
this case it switches from "User" match to "Password" match when the
return prompt is expanded to "...CDT ".

expect: does "Connected to 123.456.\n\n220 abcd FTP server (Version
4.1 Thu Jul 21 03:51:22 CDT" (spawn_id exp4) match regular expression
"(Name|login|Login|Username|User).*:.*"? no

"Unknown host"? no

"^[45]"? no

expect: does "Connected to 123.456.\n\n220 abcd FTP server (Version
4.1 Thu Jul 21 03:51:22 CDT " (spawn_id exp4) match regExpected:
'Password:'. Saw:
    while executing
"error "Expected: '$prompt'. Saw: $expect_out(buffer)""
    invoked from within
"expect -nobrace -i exp4 -re Password: {
                puts "matched on prompt"
                exp_send      "$sendString\r"
                exp_send_user "$sendString\n"
       ..."
    invoked from within
"expect {

         -i $ftpSpawnId

         -re $prompt {
                puts "matched on prompt"
                exp_send      "$sendString\r"
                exp_send_user..."

Expect should continue to expand the return prompt and it does when
called from a top level script.

expect: does "Connected to 123.456.\n\n220 abcd FTP server (Version
4.1 Thu Jul 21 03:51:22 CDT" (spawn_id exp4) match regular expression
"(Name|login|Login|Username|User).*:.*"? no

"Unknown host"? no

"^[45]"? no

expect: does "Connected to 123.456.\n\n220 abcd FTP server (Version
4.1 Thu Jul 21 03:51:22 CDT " (spawn_id exp4) match regular expression
"(Name|login|Login|Username|User).*:.*"? no

"Unknown host"? no

"^[45]"? no

..................
.................

expect: does "Connected to 123.456\n\n220 abcd FTP server (Version 4.1
Thu Jul 21 03:51:22 CDT 2005) ready.\nUser ( 10.14.142.76:(none)):
" (spawn_id exp4) match regular expression "(Name|login|Login|Username|
User).*:.*"? yes

expect: set expect_out(0,string) "User (10.14.142.76:(none)): "

expect: set expect_out(1,string) "User"

expect: set expect_out(spawn_id) "exp4"

expect: set expect_out(buffer) "Connected to 123.456.\n\n220 abcd FTP
server (Version 4.1 Thu Jul 21 03:51:22 CDT 2005) ready.\nUser
(10.14.142.76:(none)): "

send: sending "anonymous\r" to { exp4 }

Patrick Finnegan wrote:
> "(Name|login|Login|Username|User).*:.*"? no

The hitch may well be that your are not expecting
": " but ":<_zero_ or more of any character"
thus expect will return with a match after the ":"
and then send the username.
which in a lot of login implementations is too early,
it gets lost.
Same with "assword:" in contrast to "assword: ".

Due to bytecompilation scripts in a proc may run
significantly faster than in toplevel.

What happens if you change the expected prompt to:

        set prompt "(Name|login|Login|Username|User).*?: "

Or you could be even shorter with this:

        set prompt "(ame|ogin|ser).*?: "

uwe

On May 22, 2:03 am, Patrick Finnegan <finnegan.patr@gmail.com>
wrote:

One problem you should look into is your calls to expect inside your
expect. For instance your eof :

>          eof {
>                 expect *
>                 error "Expected: '$prompt'. Saw: $expect_out(buffer)"
>          }

What is the spawn_id the "expect *" supposed to use. I don't think
that the -i option of the enclosing expect applies.
More likely it will try to use a local variable spawn_id and if not
that a global. Since neither exists it chokes.  I'd
be curious to see what happens if you change your proc argument
ftpSpawnId to spawn_id.  Also if for some reason
it works the expect * will match and replace the $expect_out(buffer).
What intially matched will be gone.
Some other tips:
1. use send_user instead of puts when in expect
2.  don't nest your expects like you have
3. If you got eof  what does expect * do for you?
4. Always exp_close and exp_wait for your processes otherwise you will
eventually run out of file descriptors
5. Always  be explicit with the spawn_id  you are running an expect on
especially in procs
6. learn how to use exp_continue. it will save you alot of time.

Carl

On May 22, 2:03 am, Patrick Finnegan <finnegan.patr@gmail.com>
wrote:

I am posting this a 2nd time since Google has not seen fit to
post my first post.

I see at least 3 problems in your proc. and will explain why it
works when is it is not in "proc" form.

1. In your proc you pass in the spawn_id as ftpSpawnId thus there is
no local spawn_id variable that expect can use. You correctly use the
-i option to the first expect but the internal expects ( those written
like "expect *" ) do not inherit the outer expects spawn_id. So
without the spawn_id being defined what spawn is/are it/they expecting
on? When
the same code is run outside and the spawn command automatically
creates the spawn_id variable the "expect *" will work because it can
find a variable spawn_id. I would imagine that they will just timeout
or hang.
  ....
       "Unknown host" {
                puts "ERROR: Unknown host"
                expect *
                error "Expected: '$prompt'. Saw: $expect_out(buffer)"
         }
....

2. What is the purpose of the internal "expect *" ? If it does match
anything it will wipe out expect_out(buffer) with what it recieved. By
default globing is used and expect * will likely match on nothing and
all your print statements after that will likely print nothing. In
fact that's what Patrick saw ( message above).  Just get rid of them.

3. Use exp_send_user instead of puts.

4. Clean up is not being done. You should try to spawn and cleanup in
same proc unless you have a good reason.  Try to keep the expect as a
self contained unit. This is because expect will spawn a child but if
you do not collect ( accept the SIGCHLD signal from) the child you
will get zombies and eventually run out of spawn id's to use. So if
you get an eof, a timeout or you are done with the spawn you should
call exp_close -i $spawn_id and exp_wait -i $spawn_id . Check the man
page for options particularily for exp_wait which has a nohang option
which can come in handy.

Carl

Add to del.icio.us | Digg this | Stumble it | Powered by Megasolutions Inc