How can I set environment variables for a remote rsync process?

12

8

When I use rsync to copy files from one computer to another, an rsync process is started on both ends. However, on the remote end, shell initialization files are apparently not read, so I cannot set up environment variables for the remote rsync process. Unfortunately, there is one server that I need to rsync to on which rsync requires an environment variable in order to work. I am not an admin on the server, so I can't change the global configuration. What can I do to set environment varaibles for a remote rsync process?

Ryan C. Thompson

Posted 2010-11-04T19:43:11.583

Reputation: 10 085

How do you start the rsync process on the server? Could you trigger a script via ssh? – kraftan – 2010-11-04T21:11:15.063

When you do rsync localfilename remotehost:remotefilename, an rsync process gets started on the server. I'm not exactly sure how, but it doesn't read any shell initialization files. – Ryan C. Thompson – 2010-11-04T22:09:01.550

Answers

20

~/.profile is typically not read when you run ssh somecommand, as opposed to an interactive ssh session (or other login method where you start an interactive session).

Ssh supports sending environment variables. In OpenSSH, use the SendEnv directive in ~/.ssh/config. However the specific environment variable must be enabled with an AcceptEnv directive in the server configuration, so this may well not work out for you.

OpenSSH also allows setting environment variables on the server side. Again, this must be enabled in the server configuration, here with the PermitUserEnvironment directive. The variables can be set in the file ~/.ssh/environment. Assuming you use public key authentication, you can also set per-key variables in ~/.ssh/authorized_keys: add environment="FOO=bar" at the beginning of the relevant line.

One thing that I think always works (oddly enough) as long as you're using public key authentication is to (ab)use the command= option in the authorized_keys file. A key with a command option is good only for running the specified command; but the command in the authorized_keys file runs with the environment variable SSH_ORIGINAL_COMMAND set to the command the user specified (empty for interactive sessions). So you can use something like this in ~/.ssh/authorized_keys (of course, it won't apply if you don't use this key to authenticate):

command="export LD_LIBRARY_PATH=\"$HOME\"/lib;
         if [ -n \"$SSH_ORIGINAL_COMMAND\" ]; then
           eval \"$SSH_ORIGINAL_COMMAND\";
         else exec \"$SHELL\"; fi" ssh-rsa …

Note that I put line breaks above for legibility, but this actually needs to be all on one line.

Another possibility is to write a wrapper script ~/bin/rsync-wrapper on the server, something like

#!/bin/sh
. ~/.profile
exec rsync "$@"

Then pass --rsync-path='bin/rsync-wrapper' on the rsync command line. The argument to --rsync-path is expanded by a shell, so if you prefer you can make the rsync command line self-contained by passing something like --rsync-path='. ~/.profile; rsync'.

There is another avenue which depends on your login shell being bash or zsh. Bash always reads ~/.bashrc when it's invoked by rshd or sshd, even if it's not interactive (but not if it's called as sh). Zsh always reads ~/.zshenv.

## ~/.bashrc
if [[ $- != *i* ]]; then
  # Either .bashrc was sourced explicitly, or this is an rsh/ssh session.
  . ~/.profile
fi

## ~/.zshenv
if [[ $(ps -p $PPID -o comm=) = [rs]shd && $- != *l* ]]; then
  # Not a login shell, but this is an rsh/ssh session
  . ~/.profile
fi

Gilles 'SO- stop being evil'

Posted 2010-11-04T19:43:11.583

Reputation: 58 319

--rsync-path='. ~/.profile; rsync' work fine :) – qxo – 2016-08-05T13:07:59.400

Well, that pretty much sums it up. I hoped there was a better way than using a wrapper script. – Ryan C. Thompson – 2010-11-05T02:09:07.647

But wait a minute. If my shell init files are not being read, how can it even find the rsync binary on the server? I installed in in ~/usr, a non-standard location that I have to add to my $PATH in my shell init scripts. – Ryan C. Thompson – 2010-11-05T02:10:15.650

@Ryan: I'd actually forgotten the most direct method (see my edit), but it too requires a directive to be enabled in the server configuration. If you have found a way to take your PATH into account, you should be able to set any other variable there. (If that doesn't work, try to add as many traces as you can, starting with set -x in any shell script; replace the rsync binary by a wrapper script that dumps the environment to a file then calls the real binary.) – Gilles 'SO- stop being evil' – 2010-11-05T08:29:04.320

What about ~/.ssh/rc? – Ryan C. Thompson – 2010-11-06T22:41:08.487

@Ryan: ~/.ssh/rc is executed by a separate shell process. I think your best bet is a wrapper script or --rsync-path='. ~/.profile; rsync'. Or recompiling rsync with a suitable rpath as per your other question. – Gilles 'SO- stop being evil' – 2010-11-07T15:44:46.880

Heh, yes, I got it to recompile with a suitable rpath, which means this question is now purely academic for me. – Ryan C. Thompson – 2010-11-07T18:12:21.353

I would go for the --rsync-path wrapper solution, least dependencies needed and cannot break your ssh/shell setup by accident. – Jürgen Strobel – 2011-09-01T00:05:45.630