2

I'm running a script on a remote server like using this command:

ssh root@host 'bash -s' < script.sh

Now I'm trying to use expect to handle the password prompt. This is the script:

#!/usr/bin/expect
set cmd [lindex $argv 0]

spawn -noecho ssh root@host $cmd

expect {
  "password:" {
     send "password\r"
   }
}

If I run the script, it gives no output:

./ssh.exp 'bash -s' < script.sh

I know that's not the way to use ssh without password, but this is not the question right here.


UPDATE I tried the idea of glenn jackman with a simple script but it's not working. This is the script I'm using:

#!/usr/bin/expect
spawn ssh xxx@xxx

expect "*?assword:*"
send "pwd\r"

send "echo hello world"

This is the output I get:

[xxx@xxx bin]$ expect -d my.exp
expect version 5.43.0
argv[0] = expect  argv[1] = -d  argv[2] = my.exp
set argc 0
set argv0 "my.exp"
set argv ""
executing commands from command file my.exp
spawn ssh xxx@xxx
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {7599}

expect: does "" (spawn_id exp6) match glob pattern "*?assword:*"? no
xxx@xxx's password:
expect: does "xxx@xxx's password: " (spawn_id exp6) match glob pattern "*?assword:*"? yes
expect: set expect_out(0,string) "xxx@xxx's password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "xxx@xxx's password: "
send: sending "pwd" to { exp6 }
send: sending "echo hello world" to { exp6 }
write() failed to write anything - will sleep(1) and retry...


UPDATE I managed it to get my script to run. This is the result which works:
#!/usr/bin/expect

set user [lindex $argv 0]
set host [lindex $argv 1]
set pwd  [lindex $argv 2]

spawn ssh $user@$host bash -s

expect {
  "?asswor?: " {
    send "$pwd\n"
  }
}

while {[gets stdin line] != -1} {
    send "$line\n"
}
send \004

expect {
  "END_TOKEN_OF_SCRIPT" {
    exit 0
  }
  default {
    exit 1
  }
}
multiholle
  • 3,050
  • 8
  • 41
  • 60
  • 1
    possible duplicate of [Using expect to pass a password to ssh](http://stackoverflow.com/questions/459182/using-expect-to-pass-a-password-to-ssh) – Andrew T Finnell Apr 19 '12 at 23:10
  • From what I can tell, you don't pipe in the script, you just execute the script. Once you read the duplicate question and change your script to match you should be ok. – Andrew T Finnell Apr 19 '12 at 23:17
  • I didn't get that. Do you mean I should copy the script to the remote host to execute it? I don't want to copy the script. – multiholle Apr 19 '12 at 23:30
  • Did you forget to send the password? Add `exp_internal 1` to the top of your script. – glenn jackman Apr 20 '12 at 19:12

2 Answers2

7

You need to send the script you read on stdin to the remote host:

while {[gets stdin line] != -1} {
    send "$line\r"
}

# then you may have to send ctrl-D to signal end of stdin
send \004
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • I tried your idea, but unfortunately it doesn't work. After executing `spawn root@host 'bash -s'` I try to send some commands, but at the end I get this error: `write() failed to write anything - will sleep(1) and retry...` – multiholle Apr 20 '12 at 18:45
  • Still not working. :/ See my original question I updated the description. – multiholle Apr 20 '12 at 18:55
  • I fixed it. Thanks for your help. You can see the result in the question. – multiholle Apr 26 '12 at 20:50
0

Use expect_user, as shown in the man page:

The following script reads a password, and then runs a program every hour that demands a password each time it is run. The script supplies the password so that you only have to type it once. (See the stty command which demonstrates how to turn off password echoing.)

send_user "password?\ "
expect_user -re "(.*)\n"
for {} 1 {} {
    if {[fork]!=0} {sleep 3600;continue}
    disconnect
    spawn priv_prog
    expect Password:
    send "$expect_out(1,string)\r"
    . . .
    exit
}

Here is what I currently have, still improving it though:

#!/usr/local/bin/expect

# For debugging make the following to be line 1:
#!/usr/local/bin/expect -D 1

set timeout 20

send_user "Username?\ "
expect_user -re "(.*)\n"
set user $expect_out(1,string)

send_user "password?\ "
stty -echo
expect_user -re "(.*)\n"
stty echo
set password $expect_out(1,string)

spawn su

expect {

    "Password"  {send "$password\r"}

    "#"         {interact + return}

}