How do I pass a variable from my local server to a remote server?

24,102

Solution 1

variables are not expanded between single quotes.

use double quotes and escape the inner double quotes:

sshpass -p "password" \
  ssh [email protected] "su -lc \"cp -r $location2 $location1\";"

or close the single quotes and open them again:

sshpass -p "password" \
  ssh [email protected] 'su -lc "cp -r '$location2' '$location1'";'

bash does string concatenation automatically.

note: not tested. might screw up misserably if $locationX contains spaces or other weird characters.

Solution 2

A shell variable, is just that: a variable of the shell. The ssh command, or the shell started by sshd on the remote host have no way to get access to that variable of the client's shell.

Exported shell variables are passed as environment variables to executed commands. So if you exported location1 it would be passed as an environment variable to ssh. If you used the SendEnv ssh configuration directive (via -o or ~/.ssh/config or /etc/ssh/ssh_config...), ssh would try and send it to sshd on the remote host.

However, for that to work, sshd would need to have an AcceptEnv configuration directive that allows receiving that variable. However, it's generally not the case for security reason.

Many default ssh/sshd deployment however allow passing variables whose name starts with LC_ (for localisation). So you could leverage that with:

LC_location1=$location1 LC_location2=$location2 ssh host 
    'su -lc '\''cp -r -- "$LC_location2" "$LC_location1"'\''

Alternatively, you could have the local shell expand the variables in the command line that is passed to the remote shell:

ssh host "su -lc 'cp -r -- $location2 $location1'"

But that's the equivalent as running:

eval eval "cp -r -- $location2 $location1"

That is those variables are not passed as arguments to cp, they are interpreted (twice) as shell (the login shell of the remote user, and the sh started by su) code, so if $location1 is for instance /somewhere;rm -rf /, that will have dramatic consequences.

The proper way would be to properly escape those for the remote shell. Because of the two levels of shells, you need to escape the single quotes twice (here using ksh93/bash/zsh syntax):

escaped_location1=\'${location1//\'/\'\\\'\'}\'
escaped_location1=${escaped_location1//\'/\'\\\'\'}
escaped_location2=\'${location2//\'/\'\\\'\'}\'
escaped_location2=${escaped_location2//\'/\'\\\'\'}
ssh host "su -lc 'cp -r -- $escaped_location2 $escaped_location1'"

That assumes the login shell of the remote user is Bourne-like.

Solution 3

In addition to lesmana's answer: you should quote the variables in his second example.

sshpass -p "password" \
  ssh [email protected] 'su -lc "cp -r '\\\"$location2\\\"' '\\\"$location1\\\"'";'
Share:
24,102

Related videos on Youtube

Redson
Author by

Redson

Updated on September 18, 2022

Comments

  • Redson
    Redson over 1 year

    I am trying to pass a variable from my local server (location1) to a remote server (location2). The purpose of the code is to copy a file from the remote server from a predefined location. In simpler terms, I want to copy files from location2 to location1 using a predefined path where location1 is on the local server and location2 is a remote server. See the code segment:

    $location1=somewhere/on/local_server
    $location2=somewhere/on/remote_server
    
    sshpass -p "password" \
      ssh [email protected] 'su -lc "cp -r $location2 $location1";'
    

    The error I get is that both $location1 and $location2 are undefined. Also, I DON'T want to manually type the location paths because they could change at any time and it would be a pain to change them in the code if done manually.

    • arnefm
      arnefm about 10 years
      I am having a hard time understanding what it is you are trying to do. Are you looking for a way to transfer files between two machines? For that you can use scp. Example: scp remote-server:/home/Me/myfile.txt ~/Documents/