Remote Bash – Why Remote Bash Sources .bash_profile Instead of .bashrc

bashssh

Bash Manual says:

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.

This Bash sources ~/.bashrc:

ssh user@host :

But this Bash sources ~/.bash_profile:

ssh user@host

I don't see a difference in these two commands according to the spec. Isn't stdin connected to a network connection in both cases?

Best Answer

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.