2

My objective: Automate scp from one server to another taking inputs from user Challenge: I can not setup ssh authorized host equivalence between the servers because one user having access to target will also get access to source server So, I need to setup legacy method of providing password when prompted and then do scp.

Here is my code

L_SRC_SID=source
L_SID=target
MOUNT_POINT=app07
SERVICE_PASS=some$value
APP_SERVER_1=hostname
SRC_MOUNT_POINT=app01

#And now transfer the file over
/usr/bin/expect -c "
   set timeout 1
   cd /$MOUNT_POINT/$L_SID/apps
   spawn scp -pr * apps@$APP_SERVER_1:/$SRC_MOUNT_POINT/$L_SRC_SID/apps .
   expect yes/no { send yes\r ; exp_continue }
   expect password: { send $SERVICE_PASS\r }
   expect 100%
   sleep 1
   exit
"

exit

Challenges: 1. I am unable to assign some$value value to variable SERVICE_PASS 2. How to make the expect send script work using such a variable that has $ character in the password. It is failing with the below error.

password: can't read "value": no such variable

Any help is appreciated

I have changed the code as per suggestions, but still getting the same error

L_SRC_SID=source
L_SID=target
MOUNT_POINT=app07
SERVICE_PASS='some$value'
APP_SERVER_1=hostname
SRC_MOUNT_POINT=app01

#And now transfer the file over
/usr/bin/expect -c "
   set timeout 1
   cd /$MOUNT_POINT/$L_SID/apps
   spawn scp -pr * apps@$APP_SERVER_1:/$SRC_MOUNT_POINT/$L_SRC_SID/apps .
   expect yes/no { send yes\r ; exp_continue }
   expect password: { send $SERVICE_PASS\r }
   expect 100%
   sleep 1
   exit
"

exit

Here is the complete error.

password: can't read "value": no such variable
    while executing
"send some$value\r "
    invoked from within
"expect password: { send some$value\r }"
1
  • 1
    What will stop the users just looking at your script and seeing what the password is? There are far, far, more secure ways of copying a file under program control than this. Commented Jul 10, 2017 at 17:58

3 Answers 3

3

For this situation you will want to surround your value in single quotes:

'some$value'

Double quotes "" suppress filename expansion but not variable expansion.

$ value="some$value"
$ echo $value
 some

Single quotes '' suppress both filename and variable expansion.

$ value='some$value'
$ echo $value
 some$value

Back ticks `` allow variable Expansion

$ value=`some$value`
$ echo $value`

$

So, to suppress expansions of characters such as $, !, ", and / use single quotes!

6
  • 1
    Please don't recommend backticks. They have long been supplanted by the $(...) construct. Commented Jul 10, 2017 at 17:55
  • 1
    Nice answer, formatting is a bit messed up tho
    – ADDB
    Commented Jul 10, 2017 at 17:56
  • Thank you. Single quote working fine to retain the variable value with $ character. But my expect portion is still throwing the same error. password: can't read "value": no such variable
    – Tapan Saha
    Commented Jul 10, 2017 at 18:50
  • L_SRC_SID=source L_SID=target MOUNT_POINT=app07 SERVICE_PASS='some$value' APP_SERVER_1=hostname SRC_MOUNT_POINT=app01 #And now transfer the file over /usr/bin/expect -c " set timeout 1 cd /$MOUNT_POINT/$L_SID/apps spawn scp -pr * apps@$APP_SERVER_1:/$SRC_MOUNT_POINT/$L_SRC_SID/apps . expect yes/no { send yes\r ; exp_continue } expect password: { send $SERVICE_PASS\r } expect 100% sleep 1 exit " exit
    – Tapan Saha
    Commented Jul 10, 2017 at 19:02
  • single quote at the expect portion isn't working still. Could you please check and tell me?
    – Tapan Saha
    Commented Jul 10, 2017 at 19:11
2

Because you're using double quotes for the expect script body, you have to deal with both shell variable expansion and expect (i.e. Tcl) variable expansion. When expect is running, the shell variable has been expanded, so expect sees this:

expect password: { send some$value\r }

So now, you need to deal with Tcl variables.

You could add more quoting:

/usr/bin/expect -c "
    ...
    expect password: { send {$SERVICE_PASS}; send \r }

But that's not necessary: I would put the expect script in single quotes, and pass the shell parameters through the environment. That way, each variable will only be substituted once: either in the shell or in expect, and you won't get any surprises.

export L_SRC_SID L_SID MOUNT_POINT SERVICE_PASS APP_SERVER_1 SRC_MOUNT_POINT

/usr/bin/expect -c '  # <- single quote
    set timeout -1
    cd /$env(MOUNT_POINT)/$env(L_SID)/apps
    spawn scp -pr * apps@$env(APP_SERVER_1):/$env(SRC_MOUNT_POINT)/$env(L_SRC_SID)/apps .
    expect {
        yes/no    { send yes\r ; exp_continue }
        password: { send $env(SERVICE_PASS)\r }
    }
    expect eof
'

In general, use of sleep in expect means you either have the wrong timeout or you're expecting the wrong thing. I changed both.

1
  • This works. Excellent solution. Thank you Glenn for the response.
    – Tapan Saha
    Commented Jul 10, 2017 at 21:12
2

Use 'strong quotes'; special characters such as $, !, ", and \ have no meaning within them.

You must log in to answer this question.

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