Question

I'm using a code made my another person (we'll call it Code.x) that has a very cumbersome interactive command line interface. I often perform repetitive processes using this code and ideally I'd like to automate these tasks.

Code A asks for me to give a name for a file I want to output and then if that file name exists, it will ask me if I'd like to overwrite.

In that vein, I've written an expect script that navigates through the user prompts in Code.x:

#!/usr/bin/expect
spawn Code.x

set timeout 5
...[code]...
expect "file name" {send "foo.bar\r"} #Name of file
expect "Overwrite?" {send "y\r"} #Yes, overwrite the file
expect "Next Prompt" {send "next response\r"}
...[code]...

If the file already exists and needs to be rewritten, the rewrite prompt of course appears and everything works. However, if the rewrite prompt does not appear and instead Code.x gives the Next Prompt, I get the following error immediately after the prompt appears:

wrong # args: should be "file option ?arg ...?"
     while executing
"file"
    invoked from within
"expect "Overwrite?" {send "y\r"} #Yes, overwrite the file"

If I remove the curly braces around the send statement, the code works fine whether a rewrite is required or not. My impression from the information I've read is that the curly braces should mean that the send statement is only executed if the expect statement is satisfied. If that statement is not satisfied, I would assume that the expect code would wait until the timeout had been reached and then move on. What is actually happening here?

On another note, is is actually worth it to use expect to accomplish this task? I plan to embed this in a loop and create a number of different files.

Was it helpful?

Solution

expect "file name" {send "foo.bar\r"} #Name of file
expect "Overwrite?" {send "y\r"} #Yes, overwrite the file

Tcl (and hence expect) comments are a bit weird compared to other languages. A # is only a comment if it appears as the first character of a word that shows up where a command would appear: see http://tcl.tk/man/tcl8.5/TclCmd/Tcl.htm , rule #10

So you want an explicit semicolon to terminate the command, and then a comment can follow

expect "file name" {send "foo.bar\r"} ; #Name of file
expect "Overwrite?" {send "y\r"}      ; #Yes, overwrite the file

Here's why the error occurs: the expect command takes a list of {pattern} {action} pairs (or a single list containing "pattern action" pairs). The last pattern does not require an action. So with your misguided comments, expect saw the equivalent of this:

expect {
    "file name" {send "foo.bar\r"}
    "#Name" {of}
    "file"
}
expect {
    "Overwrite?" {send "y\r"} 
    "#Yes," {overwrite}
    "the" {file}
}

There must have been a "the" that expect saw before "Overwrite?", so it dutifully tried to execute the action block: {file}. The Tcl file command requires a subcommand, did not get one, and expect threw the error.

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