Why does remote Bash source .bash_profile instead of .bashrc
A login shell first reads /etc/profile
and then ~/.bash_profile
.
A non-login shell reads from /etc/bash.bashrc
and then ~/.bashrc
.
Why is that important?
Because of this line in man ssh
:
If command is specified, it is executed on the remote host instead of a login shell.
In other words, if the ssh command only has options (not a command), like:
ssh user@host
It will start a login shell, a login shell reads ~/.bash_profile
.
An ssh command which does have a command, like:
ssh user@host :
Where the command is :
(or do nothing).
It will not start a login shell, therefore ~/.bashrc
is what will be read.
Remote stdin
The supplied tty connection for /dev/stdin in the remote computer may be an actual tty or something else.
For:
$ ssh isaac@localhost
/etc/profile sourced
$ ls -la /dev/stdin
lrwxrwxrwx 1 root root 15 Dec 24 03:35 /dev/stdin -> /proc/self/fd/0
$ ls -la /proc/self/fd/0
lrwx------ 1 isaac isaac 64 Dec 24 19:34 /proc/self/fd/0 -> /dev/pts/3
$ ls -la /dev/pts/3
crw--w---- 1 isaac tty 136, 3 Dec 24 19:35 /dev/pts/3
Which ends in a TTY (not a network connection) as the started bash sees it.
For a ssh connection with a command:
$ ssh isaac@localhost 'ls -la /dev/stdin'
isaac@localhost's password:
lrwxrwxrwx 1 root root 15 Dec 24 03:35 /dev/stdin -> /proc/self/fd/0
The list of TTY's start the same, but note that /etc/profile was not sourced.
$ ssh isaac@localhost 'ls -la /proc/self/fd/0'
isaac@localhost's password:
lr-x------ 1 isaac isaac 64 Dec 24 19:39 /proc/self/fd/0 -> pipe:[6579259]
Which tells the shell that the connection is a pipe (not a network connection).
So, in both the test cases, the shell is unable to know that the connection is from a network and therefore does not read ~/.bashrc
(if we only talk about the connection to a network). It does read ~/.bashrc, but for a different reason.
You ask about the "why" not the "how", so I'll try to answer from that perspective. The following will be a good deal of rationale of why things happened in the past to result in how they happen today.
The reason for having two different startup files ("profile" and "rc") is that in the past the common way to work on a machine was:
Login from some kind of real terminal or other workstation and get a login shell. This shell will invoke
/etc/profile
and~/.profile
and setup the environment for the user.Invoke the environment the user wants to enter. This environment could be Xorg, but in most cases it was a multiplexer such as GNU screen.
The environment (e.g. GNU screen) would then invoke extra (non-login) shells which inherit the environment from the parent login shell.
That was the common way of logging in to a UNIX machine during the time when csh
and bash
were being developed. Therefore it was deemed wasteful to read ~/.profile
again in the shells that were inheriting the environment anyway.
bash
then added ~/.bashrc
for extra configuration for these non-login shells. csh
(and tcsh
) never added any kind of "rc" file for non-login shells. Note that csh
/tcsh
are not shells compatible with the bourne shell (which is part of POSIX) whilst bash
is. Another bourne compatible shell, ksh
, added an environment variable (called ENV
), which, if was defined would be used as a run commands ("rc") file for non-login ksh
.
So yeah, newer versions of bourne shells added the extra configuration file as a convenience for aliases and other quick options that would be present inside the shells muxed by GNU screen (or similar) but not present in the shell you get when you first enter the machine.
With the raise of graphical display managers (GDMs) the differentiation between the "profile" files and "rc" files became meaningless because the GDM would have its own initialization files (e.g. ~/.xinit
and ~/.xsession
). Then, shells stated from inside the GDM could be login or non-login shells depending of a user's whims, and the case in which a non-login shell would always have a parent that is a login shell is not true anymore.
Extra
One of my favourite tables about shell startup file comparison shows how bourne shell compatible shells use the profile
files whilst other shells doesn't. This is because in the past the initial shell (the one that started the muxer) needed to be a bourne compatible shell.