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@ -p 2222 which brew


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

    # ssh vagrant@ -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@ -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@ -p 2222 echo $PATH
  3. which itself does not seem to have a problem:

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

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

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

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

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

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

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

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)?

ssh vagrant@ -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@ -p 2222 'echo $PATH'

The same applies to:

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

As for:

ssh vagrant@ -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@ -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@ -p 2222 bash -lc brew
  • That makes sense. One strange thing... There's a difference if I run ssh vagrant@ -p 2222 /bin/bash -lc brew (ok) and ssh vagrant@ -p 2222 /bin/sh -lc brew (brew not found). Both /bin/sh and /bin/bash show the same GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15). What could be the reason? – techraf Mar 21 '16 at 6:07
  • Bash runs differently when called as sh. See the Bash manual. My guess is that you're setting the PATH in .bash_profile. – muru Mar 21 '16 at 6:10
  • And I do need that escaping... Otherwise it does not work. Does it work for you without? – techraf Mar 21 '16 at 6:11
  • .bash_profile does not exist. Paths are from /etc/paths. – techraf Mar 21 '16 at 6:13
  • @techraf since I don't use OSX, that's about all I help you with. It should work without the escaping, but maybe the old version of bash does things differently. – muru Mar 21 '16 at 6:17

When you run commands directly from ssh, you are not "logging in", you are only running a command.

Some shell scripts run when you "log in" - ~/.bashrc, /etc/profile etc.

which uses environment variables - specifically $PATH - which may be set in one of these scripts. Without $PATH, which will not know where to look.

Also, ssh vagrant@ -p 2222 echo $(which brew) will not give you what you expect - $(which brew) is interpreted by the shell, before it even gets to ssh - compare: ssh vagrant@ -p 2222 echo $(hostname) with ssh vagrant@ -p 2222 echo '$(hostname)' (note single quotes around the shell expansion). The first will get the LOCAL hostname, send it to the remote host to be echo'd. The second will be send the $(hostname) (literally) to the remote shell, to be expanded there.

UPDATE: I was slightly wrong about this.

When you run a command over ssh, ssh works out if a shell is needed (e.g. working out variables etc. If it is not needed, the binary program is run immediately. Otherwise bash is run, which may set up environment variables etc.

This is why (in your comment) brew --version fails - you don't mention a path. When you echo...; brew --version, the semicolon ; is a special shell character; ssh handles this for you, by running bash for you.

  • I'm still far from understanding this... Adding point no. (7) to the question. – techraf Mar 21 '16 at 3:45
  • Neither versions of your answer are quite right. SSH always runs a shell, but that shell does not load /etc/profile or ~/.profile if you're running a command rather than starting an interactive session. If the user's login shell is bash and you are running a command, and only on systems where it's enabled (I don't know whether that's the case on OSX), bash loads ~/.bashrc before executing the command (a bizarre complement to the normal use of .bashrc, which is for interactive non-login shells). In all other cases, .bashrc is not loaded when logging in over SSH. – Gilles 'SO- stop being evil' Jan 10 '17 at 22:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.