Passing variables in remote ssh command
LinuxBashShellSshLinux Problem Overview
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
?
Linux Solutions
Solution 1 - Linux
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.
Solution 2 - Linux
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.
Solution 3 - Linux
(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,
- an indexed array is filled (for convenience) with the names of the variables whose values you want to retrieve on the remote side.
- For each of those variables, we give to
ssh
a null-terminated line giving the name and value of the variable. - 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 [email protected] '
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"
Solution 4 - Linux
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
Solution 5 - Linux
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
Solution 6 - Linux
Escape the variable in order to access variables outside of the ssh session: ssh [email protected] "~/tools/myScript.pl $BUILD_NUMBER"
Solution 7 - Linux
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 [email protected] "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