Passing variables in remote ssh command

I want to be able to run a command from my machine using ssh and pass through the environment variable $BUILD_NUMBER

Here's what I'm trying:

ssh pvt@192.168.1.133 '~/tools/myScript.pl $BUILD_NUMBER'

$BUILD_NUMBER is set on the machine making the ssh call and since the variable doesn't exist on the remote host, it doesn't get picked up.

How do I pass the value of $BUILD_NUMBER ?

156451 次浏览

Variables in single-quotes are not evaluated. Use double quotes:

ssh pvt@192.168.1.133 "~/tools/run_pvt.pl $BUILD_NUMBER"

The shell will expand variables in double-quotes, but not in single-quotes. This will change into your desired string before being passed to the ssh command.

If you use

ssh pvt@192.168.1.133 "~/tools/run_pvt.pl $BUILD_NUMBER"

instead of

ssh pvt@192.168.1.133 '~/tools/run_pvt.pl $BUILD_NUMBER'

your shell will interpolate the $BUILD_NUMBER before sending the command string to the remote host.

Escape the variable in order to access variables outside of the ssh session: ssh pvt@192.168.1.133 "~/tools/myScript.pl \$BUILD_NUMBER"

As answered previously, you do not need to set the environment variable on the remote host. Instead, you can simply do the meta-expansion on the local host, and pass the value to the remote host.

ssh pvt@192.168.1.133 '~/tools/run_pvt.pl $BUILD_NUMBER'

If you really want to set the environment variable on the remote host and use it, you can use the env program

ssh pvt@192.168.1.133 "env BUILD_NUMBER=$BUILD_NUMBER ~/tools/run_pvt.pl \$BUILD_NUMBER"

In this case this is a bit of an overkill, and note

  • env BUILD_NUMBER=$BUILD_NUMBER does the meta expansion on the local host
  • the remote BUILD_NUMBER environment variable will be used by
    the remote shell

(This answer might seem needlessly complicated, but it’s easily extensible and robust regarding whitespace and special characters, as far as I know.)

You can feed data right through the standard input of the ssh command and read that from the remote location.

In the following example,

  1. an indexed array is filled (for convenience) with the names of the variables whose values you want to retrieve on the remote side.
  2. For each of those variables, we give to ssh a null-terminated line giving the name and value of the variable.
  3. In the shh command itself, we loop through these lines to initialise the required variables.
# Initialize examples of variables.
# The first one even contains whitespace and a newline.
readonly FOO=$'apjlljs ailsi \n ajlls\t éjij'
readonly BAR=ygnàgyààynygbjrbjrb


# Make a list of what you want to pass through SSH.
# (The “unset” is just in case someone exported
# an associative array with this name.)
unset -v VAR_NAMES
readonly VAR_NAMES=(
FOO
BAR
)


for name in "${VAR_NAMES[@]}"
do
printf '%s %s\0' "$name" "${!name}"
done | ssh user@somehost.com '
while read -rd '"''"' name value
do
export "$name"="$value"
done


# Check
printf "FOO = [%q]; BAR = [%q]\n" "$FOO" "$BAR"
'

Output:

FOO = [$'apjlljs ailsi \n ajlls\t éjij']; BAR = [ygnàgyààynygbjrbjrb]

If you don’t need to export those, you should be able to use declare instead of export.

A really simplified version (if you don’t need the extensibility, have a single variable to process, etc.) would look like:

$ ssh user@somehost.com 'read foo' <<< "$foo"

It is also possible to pass environment variables explicitly through ssh. It does require some server-side set-up through, so this this not a universal answer.

In my case, I wanted to pass a backup repository encryption key to a command on the backup storage server without having that key stored there, but note that any environment variable is visible in ps! The solution of passing the key on stdin would work as well, but I found it too cumbersome. In any case, here's how to pass an environment variable through ssh:

On the server, edit the sshd_config file, typically /etc/ssh/sshd_config and add an AcceptEnv directive matching the variables you want to pass. See man sshd_config. In my case, I want to pass variables to borg backup so I chose:

AcceptEnv BORG_*

Now, on the client use the -o SendEnv option to send environment variables. The following command line sets the environment variable BORG_SECRET and then flags it to be sent to the client machine (called backup). It then runs printenv there and filters the output for BORG variables:

$ BORG_SECRET=magic-happens ssh -o SendEnv=BORG_SECRET backup printenv | egrep BORG
BORG_SECRET=magic-happens

The list of accepted environment variables on SSHD by default includes LC_*. Thus:

LC_MY_BUILDN="1.2.3" ssh -o "SendEnv LC_MY_BUILDN" ssh-host 'echo $LC_MY_BUILDN'
1.2.3