Shell – Why some commands don’t load user environment when executed with ssh? (while other do)

environment-variablespathquotingshellssh

On a target machine (OS X El Capitan) I have brew in /usr/local/bin. When I try to get brew's path I get no result:

# ssh vagrant@127.0.0.1 -p 2222 which brew
#

Troubleshooting:

  1. brew is in /usr/local/bin/ and executes properly via ssh:

    # ssh vagrant@127.0.0.1 -p 2222 ls -l /usr/local/bin/brew
    -rwxr-xr-x  1 vagrant  admin  656 Mar 20 10:05 /usr/local/bin/brew
    # ssh vagrant@127.0.0.1 -p 2222 /usr/local/bin/brew --version
    Homebrew 0.9.5 (git revision 3a41; last commit 2016-03-20)
    
  2. There is /usr/local/bin in path:

    # ssh vagrant@127.0.0.1 -p 2222 echo $PATH
    /usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/opt/local/bin:/opt/local/sbin
    
  3. which itself does not seem to have a problem:

    # ssh vagrant@127.0.0.1 -p 2222 which bash
    /bin/bash
    
  4. Also when logged interactively to the machine I get the intended result:

    # ssh vagrant@127.0.0.1 -p 2222
    Last login: Sun Mar 20 12:02:55 2016 from 10.0.2.2
    osx-pf:~ vagrant$ which brew
    /usr/local/bin/brew
    
  5. Finally which brew works when in command substitution expression:

    # ssh vagrant@127.0.0.1 -p 2222 echo $(which brew)
    /usr/local/bin/brew
    
  6. Calling echo before which brew causes it to give the correct result:

    # ssh vagrant@127.0.0.1 -p 2222 echo test ; which brew
    test
    /usr/local/bin/brew
    
  7. Calling shell explicitly to run which brew does not change the situation:

    # ssh vagrant@127.0.0.1 -p 2222 /bin/sh -c "which\ brew"
    # ssh vagrant@127.0.0.1 -p 2222 /bin/sh -c "which\ which"
    /usr/bin/which
    

    However with explicit call to /bin/sh the "trick" from (6) no longer works:

    # ssh vagrant@127.0.0.1 -p 2222 /bin/sh -c "echo\ test\ \;\ which\ brew"
    test
    #
    

Why running which brew directly as an ssh command argument fails?

Why echo which external command in /bin/echo sees proper PATH while which does not? And why running two commands in sequence causes the second one to use environment of the first?

Is it possible to assure the environment would be loaded without referring to undocumented (I presume) workarounds like in (6)?

Best Answer

ssh vagrant@127.0.0.1 -p 2222 echo $PATH

Your local system's PATH will be printed here. You should quote the variable to prevent it from being expanded by the local shell:

ssh vagrant@127.0.0.1 -p 2222 'echo $PATH'

The same applies to:

ssh vagrant@127.0.0.1 -p 2222 echo $(which brew)

As for:

ssh vagrant@127.0.0.1 -p 2222 echo test ; which brew

which brew is run after the SSH command ends, by your local shell. That's why this didn't work:

ssh vagrant@127.0.0.1 -p 2222 /bin/sh -c "echo\ test\ \;\ which\ brew"

Side note: you don't need to do all that escaping.


The problem here might be that you're adding brew to your PATH in .profile (or .bash_profile or some similar file), which is run when a login shell is started. SSH starts a login shell only when it is run interactively, not when it's told to run a command. From man ssh:

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

You could try:

ssh vagrant@127.0.0.1 -p 2222 bash -lc brew
Related Question