Question

I'm new to expect scripts, so please forgive my stumbling...

Below is the meat of my expect script. The intent is to scroll thru several screens of output, after each of which the user is prompted with "Continue? [y/n]".

Finally, when there are no more screens, a "% " prompt is displayed, which SHOULD cause execution to fall out of the while loop.

    set more_screens 1
    while {$more_screens > 0} {  
        sleep 10
        expect {
            "\[y/n]" { send "y\r"}
            "% "  { set more_screens 0 }
        }
     }

What happens instead is... it stays in the while loop forever, sending "y" over and over and over again. I have set "exp_internal 1", and from that output it "seems" like the expect keeps re-reading text that it has already matched on, and so keeps seeing "[y/n]", and keeps sending "y" when, in fact, there are only 2 screens of output, and thus only 2 "Continue? [y/n]" prompts.

(The sleep statement is probably not necessary - i just added it to maybe solve the problem - it did NOT - and to allow me to digest the debug output better.)

Bottom line... Are there any obvious blunders in my code? I'll take any suggestions at improving this and eliminating the endless looping.

EDIT BELOW added to this question, after James made a helpful suggestion.

Thanks James for your quick response, and your helpful suggestion! But...

The same problem persists with your approach (although, yours IS much more elegant, and I'll add this to my expect tool kit.)

The problem sure seems to be, as noted initially, each execution of the expect statement RE-READS TEXT THAT WAS ALREADY READ AND COMPARED. Below is output when I execute the "exp_continue" code from James, and I set "exp_internal 1" to get debug output on my screen...

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>expect: does "get dump tables\r\n\r% get dump tables\n\r\r\nIfn  TableName           Configured >MaxUse    InUse     LastDropTime\r\n3    cdm_app             100002     190       33        >\r\n3    cdm_conv            2000002    675180    4813      \r\n3    cdm_pdisc           250002     >250002    1304      01-24-2014-19:14:59\r\n3    cdm_kpi             100001     141       25        >\r\n3    cdm_qoe             500003     204918    1578      \r\n3    cdm_qoe_hd          2500003    >582993    1578      \r\n3    cdm_kpi_error_app   100001     5         2         \r\n3    >cdm_kpi_error       100001     7         2         \r\n3    asr_cache           1000000    >1000000   999995    \r\n3    asr_sess            2000000    62670     29748     \r\n3    >asr_conn            3000000    64428     31147     \r\n3    asr_sess_keys       1500000    >1015269   1009049   \r\n3    asr_conn_opts       6000000    0         0         \r\n3    >asr_events          4000000    5239      144       \r\n3    skt_table           2000000    >2000000   2000000   \r\n3    skt_trans           1000000    408020    254674    \r\n3    >ses_sip_db          5000       0         0         \r\n3    ses_gtp_mob_txn     5000       >0         0         \r\nContinue? [y/n]:  " (spawn_id exp6) match glob pattern "[y/n]"? yes
>expect: set expect_out(0,string) "n"
>expect: set expect_out(spawn_id) "exp6"
>expect: set expect_out(buffer) "get dump tables\r\n\r% get dump tables\n\r\r\nIfn"
>send: sending "y\r" to { exp6 }
>expect: continuing expect
>
>
>expect: does "  TableName           Configured MaxUse    InUse     LastDropTime\r\n3    >cdm_app             100002     190       33        \r\n3    cdm_conv            2000002    >675180    4813      \r\n3    cdm_pdisc           250002     250002    1304      01-24-2014->\r\n3    cdm_kpi             100001     141       25        \r\n3    cdm_qoe             500003     >204918    1578      \r\n3    cdm_qoe_hd          2500003    582993    1578      \r\n3    >cdm_kpi_error_app   100001     5         2         \r\n3    cdm_kpi_error       100001     >7         2         \r\n3    asr_cache           1000000    1000000   999995    \r\n3    >asr_sess            2000000    62670     29748     \r\n3    asr_conn            3000000    >64428     31147     \r\n3    asr_sess_keys       1500000    1015269   1009049   \r\n3    >asr_conn_opts       6000000    0         0         \r\n3    asr_events          4000000    >5239      144       \r\n3    skt_table           2000000    2000000   2000000   \r\n3    >skt_trans           1000000    408020    254674    \r\n3    ses_sip_db          5000       >0         0         \r\n3    ses_gtp_mob_txn     5000       0         0         \r\nContinue? 
>[y/n]:  " (spawn_id exp6) match glob pattern "[y/n]"? yes
>expect: set expect_out(0,string) "n"
>expect: set expect_out(spawn_id) "exp6"
>expect: set expect_out(buffer) "  TableName           Con"
>send: sending "y\r" to { exp6 }
>^Csighandler: handling signal(2)
>async event handler: Tcl_Eval(exit 130)

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

After the expect matches on "[y/n]" the first time, it then does a "expect: continuing expect" (middle of the above text output), then the block of text it reads next is, except for the first few words, THE SAME TEXT BLOCK IT ALREADY READ AND COMPARED.

Am I missing anything??? This has to be a problem if the expect statements re-reads already processed output, yeah? (I have looked at the actual output sent by the target system, and it does NOT send out the same text block a second time.)

Again, I'm new at expect scripts, but I can't see any other explanation for what the debug output above shows. (And, I apologize for having trouble formatting the output correctly - I really am trying!)

Thanxks to anyone who has the patience to read all of the above, and perhaps has an explanation or suggestion.

Was it helpful?

Solution

You need to be rescued by the exp_continue command. :-)

What that command does when encountered is stay within the expect block and try to match again, with whatever new input may come.

So you can really shorten your above code to be:

expect {
    "\[y/n]" {
        send "y\r"
        exp_continue
    }
    "% " {
        # Do whatever is needed here, after which program flow will continue *outside* of the expect block
    }
}

Let me know if that works out for you!

EDIT - based on @feenyman99 additional info:

Ok, I see what it is. You have the wrong pattern. By using "[y/n]", a match is being produced with a single 'n' character. There's your matched string:

expect: set expect_out(0,string) "n"

expect_out(0,string) holds the matched pattern. expect_out(buffer) holds the portion of input removed from the buffer, which holds all input up to and including the matched pattern (from then on, the next expect operation will look for a match on input after the last matched pattern). As you can see, it holds the input up to and including the first literal 'n' character that is found (newlines don't count):

expect: set expect_out(buffer) "get dump tables\r\n\r% get dump tables\n\r\r\nIfn"

So what is happening is that your script is sending the "y\r" way before the yes/no prompt is presented. And, although I'm not seeing the rest of the logs, I'm guessing the next match happens shortly after, upon hitting the next 'n' character.

So you need to change your pattern matching statement to be able to match the yes/no prompt. Better make that a regexp match (-re). I tested the following, and it works (tested on Tcl 8.4.13):

expect {
            -re "\\\[y/n]" { send "y\r"}

The multiple backslashes are because the backslash is also an escape character within the pattern matcher. Kind of tricky, but sometimes they are needed.

Let me know how that goes. You should be all set now.

PS: This may come in handy: http://www.tcl.tk/doc/howto/regexp81.tml

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top