I've noticed that when I run a command directly on an SSH host using the ssh <host> <command> syntax, I see the output of .bashrc but not the output of .bash_profile (or .profile).

For instance, if I place the following command at the top of both files,

echo ${BASH_SOURCE[0]}

and manually source .bash_profile (which sources .bashrc in turn), I'll see

$ . .bash_profile
.bash_profile
.bashrc

This is the same output I see if I log into this computer remotely via SSH, using the ssh <host> form of the command. (And if I stow .bash_profile somewhere else temporarily, neither of these lines gets echoed.)

However, if I execute a command directly on the remote machine with the ssh <host> <command> form of ssh, then the output looks like this:

$ ssh <host> echo foo
/home/rlue/.bashrc
foo

My understanding is that the difference between .bash_profile and .bashrc is that the former is for login shells while the latter is for interactive, non-login shells.

I've concluded the following:

  1. ssh <host> sources only .bash_profile, while
  2. ssh <host> <command> sources only .bashrc, which means
  3. the former is a login shell and the latter is not.

Are these conclusions correct? Why is ssh <host> <command> treated as an interactive, non-login shell? Isn't SSH still logging into the remote machine to execute the command?

  • output of .bashrc? That file is not supposed to produce any output. Any output from .bashrc can break all tools using ssh as their transport. – kasperd Jul 2 '17 at 22:57
  • Fair enough. In this case, a couple lines in .bashrc were throwing an error, while similar lines in .bash_profile were not. I took the opportunity to investigate the discrepancy before fixing the offending lines. – Ryan Lue Jul 3 '17 at 1:15
up vote 11 down vote accepted

OpenSSH (most likely what you're running) decides whether or not to create a login shell, and it only does so if you are not running a specific command. From man ssh:

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

So it's an implementation choice for the ssh server whether it wants to create a login shell or not, and if you give a command to run, it does not.

While ssh does perform a login, if you're having it execute a command and exit, it's really much more similar to creating a shell just to run that command than it is to getting a login environment. It seems, given that, that the people writing OpenSSH decided to treat it like that sort of task.

They create a non-interactive, non-login shell to execute the command, because that's the spirit of running a command in another context/shell. Normally, though, non-interactive shells would not automatically source ~/.bashrc which is clearly happening here. bash is actually trying to help us out here. From the docs

Invoked by remote shell daemon

Bash attempts to determine when it is being run with its standard input connected to a network connection, as when executed by the remote shell daemon, usually rshd, or the secure shell daemon sshd. If Bash determines it is being run in this fashion, it reads and executes commands from ~/.bashrc, if that file exists and is readable. It will not do this if invoked as sh. The --norc option may be used to inhibit this behavior, and the --rcfile option may be used to force another file to be read, but neither rshd nor sshd generally invoke the shell with those options or allow them to be specified.

  • "...it is executed on the remote host instead of a login shell." I don't get this dichotomy. Is the command is executed on the remote host instead of in a login shell, or is the command executed on the remote host, instead of a login shell being executed there? If the former, how is it either/or? (isn't it normally both?) If the latter, it's still executed in the context of some shell, isn't it? (an interactive, non-login one?) So my question is also about semantics — what does "login shell" signify, and why would OpenSSH be designed not to create one for single commands? – Ryan Lue Jul 2 '17 at 12:40
  • @RyanLue The different "flavors" of shells each make certain tasks easier/more secure/optimized etc. While doing an ssh does require a login, the implementers apparently decided that under some circumstances, e.g., asking it to execute a command and return, do not need/benefit from the extra steps that a login shell takes, and so they skip that. So indeed there is a shell that's run, I presume mostly to setup the environment, and since the shell is not going to be provided to the user who logged in, they treat it as though the user had just started a new shell to run that command – Eric Renouf Jul 2 '17 at 12:48
  • "So indeed there is a shell that's run, I presume mostly to setup the environment..." < but I just experimented with this, and it appears that ssh <host> <command> doesn't inherit the environment of any existing login shell. For instance, $ ssh <host> \$PATH returns the path as it would be without sourcing .bash_profile (or .profile, as it were)... In a practical sense, why would you want to circumvent that step? – Ryan Lue Jul 2 '17 at 13:10
  • “...the implementers apparently decided that under some circumstances, e.g., asking it to execute a command and return, do not need/benefit from the extra steps that a login shell takes, and so they skip that.” < also, specifically looking for clarification / insight on this design choice. I define my PATH in .profile — isn't that exactly the kind of thing you'd want loaded before running an arbitrary command on a remote host? – Ryan Lue Jul 2 '17 at 13:17
  • 1
    @RyanLue the Boks ssh server distinguishes distinct uses of ssh and can grant permissions for each. Remote login, remote execution, remote copy, Maybe this helps understanding why you would have the behaviour you describe. Remote login (interactive use) might be too much to ask for in a high security environment. Openssh can be restricted by use of rbash/rksh and 'logout' in .bash_profile, or chroot. – bbaassssiiee Jul 3 '17 at 21:55

The why of this behavior lies at a lower level than shells: ssh host (the "login shell" case) uses a pseudoterminal on the remote host, to communicate between the sshd server process and the shell; ssh host command uses pipes between sshd and command, instead. Pseudoterminals are necessary to make interactive use of a command interpreter, such as a shell, or the "read-eval-print" mode of a scripting language; they implement a bunch of human-friendly features like being able to backspace over typos. But they have more overhead and (depending on configuration) do not allow arbitrary data to pass through unmodified, so SSH avoids using them when interaction is not going to be happening.

Sometimes SSH's command/no command heuristic gets this wrong; it can be overridden with the -t and -T switches. For instance, to log into a remote machine and immediately reattach a suspended screen session, you need to do ssh -t host screen -R; ssh host screen -R will cause screen to complain about not being connected to a terminal. I can't think of a situation when you would actually want to use -T, but it's there if you ever do find one.

First you need to see the different types, you can read this:

https://unix.stackexchange.com/questions/170493/login-non-login-and-interactive-non-interactive-shells

Now if you open your bashrc you are going to see at the beginning this:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

That means that depending on how are you accessing to the system this file loads the code inside or not.

  • Okay, but this raises an interesting question: .bashrc may be written so as not to be sourced if it's called in a non-interactive context (i.e., if there is no “prompt statement” / $PS1 variable). But ssh <host> <command> is decidedly non-interactive; that is, it does not raise a command prompt. So why would OpenSSH be designed to create a non-login, interactive prompt (one which tries to source .bashrc) for this seemingly login, non-interactive use case?? – Ryan Lue Jul 2 '17 at 13:15

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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