7

I would like run remote ssh commands and have them always load server-side startup files by default. I am looking for a solution that does not require:

  • configuration by root
  • adding extra boiler plate to the command each time
  • duplicating environment variables across multiple files

I am not looking to transport local environment variables to the remote shell. I want to run a remote command using the vanilla ssh <host> <command> syntax and have it run using the same environment a remote login session would get.

Background

The below assumes bash is being used for simplicity

By default, remote ssh commands start a non-interactive, non-login shell. Quoting the man page:

If command is specified, it is executed on the remote host instead of a login shell.

You can see this more explicitly on the shell by running:

# the lack of 'i' indicates non-interactive $ ssh localhost 'echo $-' hBc $ ssh localhost 'shopt login_shell' login_shell off 

But what if your remote command needs certain environment variables set? Being a non-interactive, non-login shell means neither.bash_profile nor .bashrc will be sourced.

This is problematic, for example, if you're using tools like perlbrew or virtualenv and want to use your custom interpreter in the remote command:

$ which perl /home/calid/perl5/perlbrew/perls/perl-5.20.1/bin/perl $ ssh localhost 'which perl' /usr/bin/perl 

Solutions that do not satisfy the requirements above

Explicitly invoke a login shell in the remote command

$ ssh localhost 'bash --login -c "which perl"'

Requires extra boiler plate each time

Explicitly source your profile before the command

$ ssh localhost 'source ~/.bash_profile && which perl'

Requires extra boiler plate each time

Set environment variables in ~/.ssh/environment

Requires root to enable this functionality on the server

Duplicates environment variables already set in server startup files

Set ENV and BASH_ENV

Does not work: .bash_profile and .bashrc aren't sourced

Setting in ~/.ssh/environment works, but requires root access to enable

Preface the command with the environment variables you need

Requires extra boiler plate each time (potentially a lot)

Duplicates environment variables already set in server startup files

Related posts

https://stackoverflow.com/questions/415403/whats-the-difference-between-bashrc-bash-profile-and-environment

https://stackoverflow.com/questions/216202/why-does-an-ssh-remote-command-get-fewer-environment-variables-then-when-run-man#216204

dot file not sourced when running a command via ssh

10
  • While I think this is a nice and informative question, I do not think it is a good fit for the site. "Best" is going to subjective.
    – jordanm
    CommentedMar 25, 2015 at 18:56
  • @calid, simplify your question to "how to transport my environment to a remote ssh session", and then provide an answer with the possibilities. That would be a useful question.CommentedMar 25, 2015 at 18:58
  • @jordanm point taken on Best, I've replaced it with Elegant. In terms of subjective question in general, all the solutions (at least I know of) are objectively cumbersome simply in terms of required setup or boiler plate required.. would be nice to know if there's any solution that is less cumbersome.CommentedMar 25, 2015 at 19:00
  • @glennjackman I feel like that has largely been covered elsewhere (see for example the second link in Related Posts). I'd really like to know if there's a simple solution to this problem.CommentedMar 25, 2015 at 19:02
  • @jordanm I've edited the post. The issue with being "primarily opinion-based" should be resolved.CommentedMar 25, 2015 at 23:49

2 Answers 2

2

Create a wrapper shell function sshc which prefixes the source ~/.bash_profile boiler plate for you:

function sshc { local host=$1 local cmd=$2 ssh $host "source ~/.bash_profile && $cmd" } 

You can then use this as:

$ sshc localhost 'which perl' /home/calid/perl5/perlbrew/perls/perl-5.20.1/bin/perl 
1
  • Just occurred to me as I was walking over to get my coffee. The only downside is this is a client-side thing, not a one-time server-side solution.CommentedMar 25, 2015 at 19:40
2

bash does read ~/.bashrc though even when non-interactive when invoked over ssh when compiled with #define SSH_SOURCE_BASHRC as it is on Debian and derivatives at least (a misfeature IMO, but comes handy to you here).

So you could add to the top of ~/.bashrc on the remote host:

if [ -n "$SSH_CLIENT" ] && [ "$SHLVL" = 0 ] && [ -n "${-##*[il]*}" ]; then . /etc/profile . ~/.bash_profile fi 
1
  • Confirmed it works for me. The first command in stock .bashrc is usually preceded by a comment # If not running interactively, don't do anything. If you put anything before that line, it will be executed before command when running ssh host command.
    – raj
    CommentedJul 12, 2022 at 15:02

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.