Whats the Difference Between a Login and a Non-Login Shell?
I always kind of knew there was a difference between login and non-login shells, but when I couldn’t explain the difference properly to a coworker, I knew I needed to spend some time on figuring it out.
The difference is addressed nicely in the book Unix Power Tools (Oreilly):
When you first log in to a Unix system from a terminal, the system normally starts a login shell. A login shell is typically the top-level shell in the “tree” of processes that starts with the
init
process. Many characteristics of processes are passed from parent to child process down this “tree” — especially environment variables, such as the search path. The changes you make in a login shell will affect all the other processes that the top-level shell starts — including any subshells.So, a login shell is where you do general setup that’s done only the first time you log in — initialize your terminal, set environment variables, and so on. […]
So you could think about a login shell as a shell that is started at
startup by the init
process (or systemd
nowadays). Or as a shell
that logs you into the system by your providing a username and a
password. A non-login shell, by contrast, is a shell that is invoked
without logging anybody in.
Is My Current Shell a Login Shell?
There are two ways to check if your current shell is a login shell:
First, you can check the output of echo $0
: if it starts with a dash
(like -bash
), it’s a login shell. Be aware, however, that you can
start a login shell with bash --login
, and echo $0
will output just
bash
without the leading dash, so this is not a surefire way of find
out if you are running a login shell.
Secondly, the Unix StackOverflow offers this way of finding out:
$ shopt -q login_shell && echo login || echo nonlogin
(-q
suppresses the output of the shopt
command.)
The Difference Between Login and Non-Login That Actually Matters
Practically speaking, the difference between a login shell and a
non-login shell is in the configuration files that Bash reads when it
starts up. In particular, according to man bash
:
[…] it first reads and executes commands from the file
/etc/profile
, if that file exists. After reading that file, it looks for~/.bash_profile
,~/.bash_login
, and~/.profile
, in that order, and reads and executes commands from the first one that exists and is readable.
You can observe this behavior by putting echo
commands in
/etc/profile
, ~/.bash_profile
, ~/.bash_login
and ~/.profile
.
Upon invoking bash --login
you should see:
echo from /etc/profile
echo from ~/.bash_profile
$
If the shell is a non-login shell, Bash reads and executes commands from
~/.bashrc
. Since we are starting a non-login shell from within a login
shell, it will inherit the environment. Sometimes, this will lead to
confusion when we inadvertently get a login shell, and find out that our
configuration from ~/.bashrc
is not loaded. This is why many people
put something like the following in their .bash_profile
:
[[ -r ~/.bashrc ]] && source ~/.bashrc
This test whether .bashrc
is readable and then sources it.
Why You Sometimes Want a Login Shell
When you switch users using su
you will take the environment of the
calling user with you. To prevent this, you should use su -
which is
short for su --login
. This acts like a clean login for a new user, so
the environment will not be cluttered with values from the calling user.
Just as before, a login shell will read /etc/profile
and the
.bash_profile
of the user you are switching to, but not its .bashrc
.
This post on
StackOverflow shows why
you might want to prefer to start with a clean environment (spoiler:
your $PATH might be “poisoned”).
Conclusion
In this article we saw that the main difference between a login and a non-login shell are the configuration files that are read upon startup. We then looked at what the benefits are of a login shell over a non-login shell.