bramford
bramford

Reputation: 67

expect Interact reads the matched line over and over again without moving onward

I have the following expect script to:

#!/usr/bin/expect
set hostname [lindex $argv 0]
set working_dir [lindex $argv 1]
set package [lindex $argv 2]
set tcl_test $working_dir/$package.tcl
set config $working_dir/$package.config
set logdir $working_dir/$package
set timeout 30
set prompt "\~\\\]\\\$"

eval spawn ssh $hostname
expect {
    -re "(yes/no)" {send "yes\r"}
    -re "password\:" {      
        interact {
            -o
            -re $prompt {send "export VARIABLE1=$working_dir\"\r"}
            -re $prompt {send "issue-test-command -config $config -module $tcl_test\r"}
        }
    }
}

The password match and interact works correctly. As soon as $prompt is matched, the environment variable export command is issued:

-re $prompt {send "export VARIABLE1=$working_dir\"\r"}

This is correct, but then rather than moving on to the line:

-re $prompt {send "issue-test-command -config $config -module $tcl_test\r"}

The same line is read, the pattern is matched again and the same command is performed. This results in a permanent loop of issuing the same command.

How can I force interact to move on to the next line, or use a different expect built-in to achieve what I'm after?

Upvotes: 0

Views: 1655

Answers (2)

Donal Fellows
Donal Fellows

Reputation: 137787

If you provide the same pattern multiple times, only one of the associated arms gets executed. More complex things have to be written out in full (e.g., with a little state machine).

But I think you're making that code rather too complex. The only place where you ever really want to interact is once you've got the program started, and the only place where you might need a multi-arm expect is when there are multiple things that might happen at that point in the interaction. Let's write it more simply, but with the use of exp_continue. (I omit the setting of variables…)

eval spawn ssh $hostname
# Manage the login sequence, with its optional host check and optional password
# (that's optional in case someone decides to properly set up RSA keys)
expect {
    -ex "(yes/no)" {      # Exact match here
        send "yes\r"
        exp_continue
    }
    -ex "password:" {     # Exact match here
        send "$password\r"
        exp_continue
    }
    -re $prompt {         # RE match here
        # Do nothing; fall out of the expect as we're now logged in...
    }
}

# We're now at a prompt; make things work as desired
send "export VARIABLE1=\"$working_dir\"\r"
expect -re $prompt
send "issue-test-command -config $config -module $tcl_test\r"

# Now we're ready to let the user talk to the program...
interact

Upvotes: 1

glenn jackman
glenn jackman

Reputation: 247210

Imagine you're giving instructions to someone:

  1. if you see a red light then stop
  2. if you see a red light then go

You wouldn't be surprised if they get confused. That's what you're doing to Expect with multiple -re $prompt branches. However Expect just takes the first instruction you tell it.

Try this:

    interact {
        -o
        -re $prompt {
            send "export VARIABLE1=\"$working_dir\"\r"
            send "issue-test-command -config $config -module $tcl_test\r"
        }
    }

BTW:

  1. you're missing exp_continue after send "yes\r"
  2. you're sending the wrong number of double quotes on the export command

Upvotes: 2

Related Questions