3

I'm trying to send special characters (password) which contains #?!k;|C . The password is dynamic and cannot be hardcoded in the script, so I'm passing it as variable as shown below

$ expect ./passwordlessSSH.exp $hostname "$password"

the code of this script is as below

#!/usr/bin/expect -f
 set host [lindex $argv 0]
set pass [lindex $argv 1]

spawn ssh-copy-id -i /home/hdpsvcs/.ssh/id_rsa.pub hdpsvcs@$host
expect {
  "yes" {
    send "yes\r"
  }
    "assword" {
    send "$pass \r"
}
exit 0

But still it is not running the script properly. I don't see any error but the variable is not passed correctly. The output is as shown below:

$ expect ./passwordlessSSH.exp $hostname "$password"

 spawn ssh-copy-id -i /home/hdpsvcs/.ssh/id_rsa.pub test@otesthost
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed:
"/home/test/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are     prompted now it is to install the new keys
\S
Kernel \r on an \m
test@test's password: 
$
5
  • IN simple words I'm not able to run below command send ";c39#?!K|;p;abc\r" and I cannot use back slashes as the password is going to be a variable Commented Jul 17, 2019 at 12:34
  • 2
    Make sure you write "$pass\r" without a space, not "$pass \r". Also, add a short sleep before the send to allow the remote script to switch off echo (and flush the tty).
    – meuh
    Commented Jul 17, 2019 at 12:44
  • Hi meuh, I gave without space. Still the same issue Commented Jul 17, 2019 at 13:04
  • 2
    I see no evidence that the password is sent incorrectly. However, you exit right after you log in. Perhaps you want to change exit 0 to interact so you can remain logged in. Commented Jul 17, 2019 at 13:30
  • 1
    @meuh, a sleep should not be necessary. Commented Jul 17, 2019 at 13:32

3 Answers 3

3

After plenty of searching, I realized I couldn't use expect with special character unless i escaped. Convert password with special characters for use with expect script gives a short perl script that allowed me to handle special characters programatically in dynamic passwords.

#/bin/sh
pstr='$x%y!zpass' # plain, un-escaped string
estr=$(perl -e 'print quotemeta shift(@ARGV)' "${pstr}")
echo ${estr}      # show escaped string

produces:

\$x\%y\!zpass

Edit: I was unable to send it to an expect script from the command line, so feel free not to accept this as the answer, but using the above did work for me by sending arguments to a bash script, that in turn invokes the expect script. Here's how I'd apply it to the OP's code.

Bash script: passwordlessSSH.sh

#/bin/sh
hostname=$1
pstr=$2 # plain, un-escaped string
estr=$(perl -e 'print quotemeta shift(@ARGV)' "${pstr}")
echo ${estr}      # show escaped string
/your/script/location/passwordlessSSH.exp $hostname ${estr}

Expect Script: passwordlessSSH.exp

#!/usr/bin/expect -f
set host [lindex $argv 0]
set pass [lindex $argv 1]

spawn ssh-copy-id -i /home/hdpsvcs/.ssh/id_rsa.pub hdpsvcs@$host
expect {
  "yes" {
    send "yes\r"
   }
    "assword" {
    send "$pass \r"
}
exit 0

To execute: Just execute the bash script

./passwordlessSSH.sh $hostname "$password"

4
  • 1
    But the question isn’t about how to echo a string;  it’s about how to send it from an expect script. Commented Feb 10, 2020 at 3:49
  • @Scott it looks to me as if Byte is saying that the password should be "escaped" using this method before passing it on to expect. Byte, correct me if I've misunderstood. It might make it more obvious if you demonstrated the OP's example of expect ./passwordlessSSH.exp $hostname "$password"
    – Jeff Schaller
    Commented Feb 10, 2020 at 14:29
  • 1
    @JeffSchaller: If that’s what Byte is trying to say, then I suspect that the answer is wrong. But I don’t currently have access to a system with expect, so I can’t test it right now. Commented Feb 11, 2020 at 23:23
  • in this example, i had to run ' set +o histexpand' from the bash prompt to use ! in a password, else it'd attempt to read it as a bash history command.
    – Byte
    Commented Feb 12, 2020 at 19:34
0

Not sure why the respondent suggested using perl, as expect can handle this fine as an environment variable. Example:

export IN=file1
export OUT=file2
export PASS='!@#$%^&*('
expect -c '
    set timeout -1
    spawn openssl enc -d -aes-256-cbc -salt -in "$env(IN)" -out "$env(OUT)"
    match_max 100000
    expect "password:"
    send -- "$env(PASS)\r"
    expect "password:"
    send -- "$env(PASS)\r"
    expect eof
    puts "$expect_out(buffer)"' #> /dev/null 2>&1
0

You can use printf in bash to convert string to escaped, like:

#!/bin/bash
pstr=$1
escaped_pstr=$(printf '%q' "$pstr")
echo $escaped_pstr

This script will print escaped string:

# sh test.sh '$x%y!zpass'
\$x%y\!zpass

And there is all my code:

#!/bin/bash

pstr=$1
escaped_pstr=$(printf '%q' "$pstr")

cat > /usr/bin/sshpswd << eof
#!/usr/bin/expect
spawn ssh -o StrictHostKeyChecking=no sshuser@$DNS_MGNT_IP
expect {
    "*password*" {send "$escaped_pstr\r";}
}
interact
eof
 
chmod +x /usr/bin/sshpswd
sshpswd

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .