2

Before anyone says to use public keys, this isn't an option as I'm dealing with customer servers.

I have a script that maintains a file with all of the IP/username/passwords of my customer's servers. Through the script I select a server and use a here document with expect to log in to that server.

#### Code up here to set the variables.
exp_internal 1
/usr/bin/expect << EOFFF

if { $USE_TUNNEL == 1 } {
        spawn ssh -L 4567:localhost:3306 $user\@$ip
} else {
        spawn ssh $user\@$ip
}
expect {
    -re ".*es.*o.*" {
        exp_send "yes\r"
        exp_continue
    }
    -re ".*sword.*" {
        exp_send "$pass\r"
    }
}
expect {
    "$ " { send "<<<Send stuff>>>" }
    "# " { send "<<<Send stuff>>>" }
}
interact
EOFFF
# End of bash script

My problem is that after the here document ends, it closes the SSH session and drops me back to my local server. I'd like to hold the remote ssh session open.

EDIT I added exp_internal 1 before the if { $USE_TUNNEL == 1 } { The end of the output is below:

spawn ssh ****@***.***.***.***
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {22819}

expect: does "" (spawn_id exp4) match regular expression ".*es.*o.*"? no
".*sword.*"? no
****@***.***.***.***'s password:
expect: does "tms6@161.19.242.206's password: " (spawn_id exp4) match regular expression ".*es.*o.*"? no
".*sword.*"? yes
expect: set expect_out(0,string) "****@***.***.***.***'s password: "
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "****@***.***.***.***'s password: "
send: sending "***********\r" to { exp4 }

expect: does "" (spawn_id exp4) match glob pattern "$ "? no
"# "? no


expect: does "\r\n" (spawn_id exp4) match glob pattern "$ "? no
"# "? no
Last login: Thu Jun  4 13:39:10 2015 from ***.***.***.***

expect: does "\r\nLast login: Thu Jun  4 13:39:10 2015 from ***.***.***.***\r\r\n" (spawn_id exp4) match glob pattern "$ "? no
"# "? no
[***@********* ~]$
expect: does "\r\nLast login: Thu Jun  4 13:39:10 2015 from ***.***.***.***\r\r\n\u******@*********:~\u001b\[****@********* ~]$ " (spawn_id exp4) match glob pattern "$ "? yes
expect: set expect_out(0,string) "$ "
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "\r\nLast login: Thu Jun  4 13:39:10 2015 from ***.***.***.***\r\r\n\**********@*********:~\u001b\[***@**************** ~]$ "
send: sending "mylist TerminalProfile | cut -d'"' -f6\r" to { exp4 }
interact: received eof from spawn_id exp0
[*****@********** sign_on_one_file]$

I'm dealing with customer servers so I apologize for blanking out all of the IP/usernames/hostnames/passwords.

So we're clear, The last line when it drops me back to the prompt is the prompt of my local machine. not the remote I was attempting to log in to.

When I extract the expect script out into a separate file and just call that as the last line of the bash script it works as intended. I'd like to have it all in one file though to ease distribution of the script to my co-workers.

EDIT 2 The <<Send stuff>> is just a function that is on ever server my company owns. it is a wrapper to print a mysql table as a csv.

expect {
    "$ " { send "mylist TerminalProfile | cut -d'\"' -f6\r" }
    "# " { send "" }
}
interact
CodeCorrupt
  • 175
  • 13
  • The stuff you send, perchance does it include "exit"? "interact" is the right thing. – glenn jackman Jun 04 '15 at 00:37
  • No, All it does is run a script that echos the servers name and some additional info. – CodeCorrupt Jun 04 '15 at 15:10
  • add `exp_internal 1` before you spawn. See what the debugging output shows you. – glenn jackman Jun 04 '15 at 15:16
  • I've updated my question to include the output after adding `exp_internal 1` – CodeCorrupt Jun 04 '15 at 19:59
  • Everything looks good up until the interact. It seems that the problem is in "send stuff" which you haven't shown. Be aware that by putting the expect body in an unquoted [heredoc](https://www.gnu.org/software/bash/manual/bashref.html#Here-Documents), you are affected by bash expansions. Can you share the "send stuff" part of your script? – glenn jackman Jun 04 '15 at 21:26
  • The `-d` output shows `interact: received eof from spawn_id exp0` which indicates the spawned process has exited. – pynexj Jun 05 '15 at 01:39
  • Sure, It's a custom function on all of my companies servers that just outputs a database table in a comma separated list. See edit above – CodeCorrupt Jun 23 '15 at 13:31

1 Answers1

6

I think we have the same problem caused by mixing "interact" and EOFFF together. "Interact" tells expect script to read from stdin, meanwhile EOFFF in your case means stdin is closed, then you got

"received eof from spawn_id exp0"

According to this Embedding an expect inside a bash script, currently below solution is good to me:

expect <(cat <<'EOD'
spawn ... (your script here)
EOD
)

The EOD ends the here-document, and then the whole thing is wrapped in a <( ) process substitution block. The result is that expect will see a temporary filename including the contents of your here-document.


Two other solutions:

  1. Use a temporary file to save the expect script then execute the script
  2. Use "-c" option of expect, put your expect commands following "-c"

I also looks forwards some other methods, would you let me know yours?

Qiu Yangfan
  • 871
  • 11
  • 25