Issues with Expect Script

Hi,

does the expect script tries to match for everyline on the screen irrespective of the prompts???

spawn ./Inst.sh
expect "path? (Y/N)"
send "Y\r"
expect "folder path"
send "$DIR1\r"
expect "path? (Y/N)"
send "Y\r"
expect "folder path2"
send "$DIR2\r"

After the installer begins.. it displays various lines before the first expect.
But the script tries to match for every line that is displayed before the 1st and timeouts.

1)Why does it tries to match for every lines that is out in the screen?

expect: does "" (spawn_id exp5) match exact string "path? (Y/n)"? no
Native ignore this if not using solaris OS.no stlport in java.library.path
expect: does "Native ignore this if not using solaris OS.no stlport in java.library.path" (spawn_id exp5)
 match exact string "path? (Y/n)"? no

when it finds the actual matches - the send is passed

expect: does ".............................path? (Y/n) \r\n" (spawn_id exp5) match glob pattern "path? (Y/n)"? yes
 expect: set expect_out(0,string) "path? (Y/n)"
expect: set expect_out(spawn_id) "exp5"
 send: sending "Y\r" to { exp5 }

2) and also it appends the previous results to next and the expect statement is appended recursively

expect: does " \r\n" (spawn_id exp5) match glob pattern "folder path"? no
Y
expect: does " " (spawn_id exp5) match glob pattern "folder path$"? no
expect: does " \r\n" (spawn_id exp5) match glob pattern "folder path$"? no
Y
expect: does " \r\nY\r\n" (spawn_id exp5) match glob pattern "folder path$"? no
folder path:
expect: does " \r\nY\r\n\r\nfolder path: \r\n" (spawn_id exp5) match glob pattern "folder path$"? no
expect: timed out
send: sending "/path/xx\r" to { exp5 }

because of this the expect statements gets varying including the newlines and the order is not maintained.

what is that i'm missing here?

thanks

You need \r at the end of expect commands, i.e. expect "path? (Y/N)\r"

To avoid matching you previous send commands use set stty_init -echo near the top of your script.
If your prompts can vary order you could try matching them all in one multi choice expect command. In the below example I can match on any one of the three prompts and loop until and eof is found:

#!/usr/bin/expect --
set stty_init -echo
set DIR1 { /path/xx }
set DIR2 {/path/yy }

spawn ./Inst.sh

while {1} {
   expect {
       "path? (Y/N)" { send "Y\r" }
       "folder path" { send "$DIR1\r" }
       "folder path2" { send "$DIR2\r" }
       eof { break }
   }
}
1 Like

Thanks, i did tried setting set stty_init -echo and \r at the end.
But still the previous expects are concatenated recursively.

Issue :1
Actual expect "path"?

But from autoexpect when i tried to look for the actual expect

expect: does "" (spawn_id exp5) match exact string "path? (Y/n)"? no
Native ignore this if not using solaris OS.no stlport in java.library.path
expect: does "Native ignore this if not using solaris OS.no stlport in java.library.path" (spawn_id exp5)
 match exact string "path? (Y/n)"? no

Changing expect to
expect "Native ignore this if not using solaris OS.no stlport in java.library.path. path? (Y/n)" then only it matches and sends the response.
i tried regex to shorten this as the other expects concatenates huge stmts and timeout occurs.

This is how expect works it will continue building it's buffer until it encounters the string it is looking for:

expect: does "" (spawn_id exp5) match exact string "path? (Y/n)"? no
Native ignore this if not using solaris OS.no stlport in java.library.path
expect: does "Native ignore this if not using solaris OS.no stlport in java.library.path" (spawn_id exp5)
 match exact string "path? (Y/n)"? no

See here your statement was expect "path? (Y/N)" , the input buffer will continue to grow until it finds a match for this, or after a default of 10 seconds it will timeout.

If you are timing out it could be you are trying to match to the wrong prompt; or (what it sounds like in your case) the install script is taking a long time to get to the next prompt in which case you may just need to extend the timeout eg:

pawn ./Inst.sh
expect "path? (Y/N)"
send "Y\r"

# Install does a lot of stuff here after the path? (Y/N) prompt above
# so we extend the timeout to 20 seconds
set timeout 20
expect "folder path"
send "$DIR1\r"

# restore the timeout back to default (10 seconds)
set timeout 10
expect "path? (Y/N)"
send "Y\r"
expect "folder path2"
send "$DIR2\r"

Thanks!

when i tried to provide exact request- before the timeout happens it kind of matched.But does it has to be always the "exact" as few expects - they are longer. and even after increasing timeout it doesnt match for a shorten statements

Actually for every next expect the installer does lot of stuffs

pawn ./Inst.sh
expect "\r\npath? (Y/N) "
send "Y\r"
send "\r\n$DIR1: "
expect "\r\npath? (Y/N) "
send "Y\r"
expect "\r\n\r\nfolder path2 : "
send "$DIR2\r"
expect "\r\r\n---------------------------------------------\r\nlicense-----(y/n) : "
send ""Y\r"

for the license expect - only if the full statement it matches and doesnt work for
expect "license (y/n):"

Thanks.

For matching your license prompt I'd be tempted to use a regular expression like:

expect -re {-{10}\r\nlicense-+\(y/n\) : }

This is a little complex and need some explanation.

Firstly I usually quote my regular expressions in expect (and tcl) with { and } instead of double quotes ( " ).
This is because regular expressions tend to contain a lot of special characters which would otherwise be evaluated by tcl,
angled brackets suppress any expansion on the strings within them think of them as the same as single quotes in shell scripts.

So the above can be thought of as saying match the regular expression -{10}\r\nlicense-+\(y/n\) :

-{10} = exactly ten hyphen characters, we could have simply used ---------- instead but this is shorter

-+ = one (or more) hyphen characters; plus symbol in a regular expression means repeat the proceeding expression one or more times

\(y/n\) round brackets are special characters to a regular expression characters so we use backslash to quote them. They then simply match regular bracket characters.

So what sort of strings will the RE match?

Here are 3 examples:

-------------------------
license-(y/n) :

----------
license---------------------------(y/n) :

----------IGNORED--TEXT----------
license---------------------------(y/n) :

Thanks for the detailed explanation and that worked perfectly!!!
i just had to add another escape for "/" between y/n .{\(y\/n\)}.

Before the license prompt, the installer may exit for few validations. Though the below code works, i don't want to put them in while loop as it starts to validate for all expects. Since we knew the order except that it may or may not occur is there a way to read from output buffer and to check ?

spawn ./Inst.sh
expect "\r\npath? (Y/N) "
send "Y\r"
send "\r\n$DIR1: "
expect "\r\npath? (Y/N) "
send "Y\r"
expect "\r\n\r\nfolder path2 : "
send "$DIR2\r"
while {1)
{
expect 
-exact "no space" {exit 1}
-exact "not latest" {exit 1}
-re {-{10}\r\nlicense-+\(y\/n\) : }
send "Y\r"
-exact "\r\n\r\nfolder path2 : "
send "$DIR2\r"
eof {break}
}

Since the actual install would take around 4-5hrs,is the below while loop is advisable for long running installations?
are there any better way of implementing it , to avoid the loop expects matching for all commands everytime.

spawn ./Inst.sh
expect "\r\npath? (Y/N) "
send "Y\r"
send "\r\n$DIR1: "
expect "\r\npath? (Y/N) "
send "Y\r"
expect "\r\n\r\nfolder path2 : "
send "$DIR2\r"
while {1)
{
expect 
-exact "no space" {exit 1}
-exact "not latest" {exit 1}
-re {-{10}\r\nlicense-+\(y\/n\) : } send "Y\r"
-exact "\r\n\r\nfolder path2 : "send "$DIR2\r"
eof {break}
}

This approach seems fine expect keeps a fairly limited buffer (2000 characters by default) so it's not like it would be using heaps of memory.

You could also limit break out of the loop based on a certain strings in the input (e.g. === Unpacking Complete === ) and then resume your normal single expect approach something like this:

...
while {1)
{
   # Lots of output here while unpacking - can take 4-5 hrs !
   expect 
        -exact "no space" {exit 1}
        -exact "not latest" {exit 1}
        -exact "\r\n=== Unpacking Complete===" { break }
}

expect -re {-{10}\r\nlicense-+\(y\/n\) : }
send "Y\r"
-exact "\r\n\r\nfolder path2 : "
send "$DIR2\r"

Thanks for the response.
But the challenge is i get timeout when i try to put the install out of while.
after the license prompt is the actual install starts.and thats where i could find the best break.
Hence now the installation steps tries to match with last expect and it timeouts.

...
while {1)
{
       expect 
        -exact "no space" {exit 1}
        -exact "not latest" {exit 1}
       - expect -re {-{10}\r\nlicense-+\(y\/n\) {send "Y\r"" ; break }
}
###LOTS OF ACTIONS takes here 4hrs ####
-exact "\r\n\r\nfolder path2 : "
send "$DIR2\r"
expect: does "----------------------------------------\\r\n----------------
------------------------\r\nBeginning installing of data packs.\r\n\r\nUnzipping FILE1 and installing\r\n+\r\nUnzipping FILE2 and installing\r\n++++\r\nUnzipping FILE3 and installing\r\n++" (spawn_id exp5) match exact string "\r\n\r\nfolder path2:"? no
expect: timed out
send: sending "/XX/XX/XXXX\r"

I can try adding timeout expect- but how to proceed with the install?

I can't see any problem here with increasing the timeout before looking for the path2 prompt eg:

...
while (1) {
   expect {
       -exact "no space" { exit 1 }
       -exact "not latest" { exit 2 }
       eof { exit 3 }
       -re {-{10}\r\nlicense-+\(y\/n\)} {send "Y\r" ; break }
   }
}
## LOTS OF ACTIONMS here  4hrs ###
# 16200 seconds = 4.5 hours
set timeout 16200

expect {
   -exact "\r\n\r\nfolder path2 : " {send "$DIR2\r"}
# Consider trapping other error strings here so we detect issues before the 4.5h timeout!
   timeout {exit 4}
   eof {exit 5}
}
expect eof

Downside is if you have some unexpected error message with a prompt the script will wait 4.5 hours before timing out. If program closes the eof will trap this fine, but it waits from some sort of acknowledgment etc. the timeout then applies.

1 Like