multiholle
multiholle

Reputation: 3160

Expect redirect stdin

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
  }
}

Upvotes: 3

Views: 10697

Answers (2)

LinuxBlack
LinuxBlack

Reputation: 1

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}

}

Upvotes: 0

glenn jackman
glenn jackman

Reputation: 246774

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

Upvotes: 7

Related Questions