bashexpect

What is the difference between referencing a HEREDOC and a File when using expect


I have a script that connects to servers via ssh using expect and issues some commands.

When I run the expect script as HEREDOC it quits with an eof by the spawned shell after entering the Password, on the other hand when I run exactly the same script as a file it gives me a shell, how can this be?

I try to use this snippet:

expect -d /dev/stdin <<- END
sleep 10
set timeout 20
eval spawn "ssh user@example.org"

expect "user@example.org's password: " { send -- "Passw0rd\r" }

interact
END

But everytime I try to connect I get an 'received eof' and and expect exits, no shell.

expect: does "\ruser@example.org's password: " (spawn_id exp6) match glob pattern "rmh@user@example.org's password: "? yes
expect: set expect_out(0,string) "rmh@user@example.org's password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "\rrmh@user@example.org's password: "
send: sending "Passw0rd\r" to { exp6 }
interact: received eof from spawn_id exp0

On the other hand when I open exactly the same script as a file I get connected.

cat <<- END > interact.expect
sleep 10
set timeout 20
eval spawn "ssh ssh user@example.org"

expect "user@example.org's password: " { send -- "Passw0rd\r" }

interact
END

expect -d interact.expect

I tried multiple times and double checked the scripts being identical.

Could someone explain how this could be?


Solution

  • The difference is what happens when you get to the interact statement. This tells expect to connect its stdin to the pty that's feeding to the current command.

    When expect is reading from a file, its stdin is still connected to the terminal, so interact will allow you to interact with the command using the terminal.

    But when you use the here-doc, stdin is connected to the here-doc, the terminal connection is lost to the expect process. So expect gets EOF because you've reached the end of the here-doc.

    You would see the same thing if you used redirection to read from the file instead of using a filename argument:

    expect -d /dev/stdin < interact.expect