The most common problem caused by misuse of shell startup files is that if you define environment variables in .bashrc
as opposed to .profile
, they are not defined in applications that are not launched from a shell in a terminal but rather from a GUI menu.
Defining environment variables from .bashrc
is generally not a good idea, but that's primarily because it's generally useless as the variables should already have been set at login time. It can cause a problem in practice if you (or an application) have deliberately changed the value of a variable (e.g. PATH
) in a program and you launch a shell from that program and expect the setting to have remained the same.
You can avoid the problem of environment variables being reset by defining a “sentinel” value, and not defining anything if the sentinel value is set:
if [ -z "$JMLANE_PROFILE_READ" ]; then
export ...
export JMLANE_PROFILE_READ=1
fi
Another problem caused by terminals starting login shells is that there are things that should only be done once when you log in, for example starting a password agent (e.g. ssh-agent
), or initiating a session (e.g. running startx
in certain circumstances). The sentinel variable avoids these issues.
A shell inside a terminal is always interactive. As long as you source .bashrc
from .bash_profile
when the shell is interactive, you don't need to worry about the terminal starting a login shell.
An additional wart of bash's startup file handling is that .bashrc
is read by non-interactive shells invoked by rshd or sshd. For example, when you do rsync somefile host.example.com:
, if your login shell on host.example.com
is bash, you can use .bashrc
there to set the path to include rsync
. You can tell you're in this situation because .bashrc
is read from a non-interactive shell.
## .bashrc
if [[ $- != *i* ]]; then
# either .bashrc was executed explicitly or this is a noninteractive rsh/ssh session
fi
These are my thoughts on the different "types"of shells -- unfortunately I didn't witnessed the rise of the Un*x right from the beginning (I assume this concept is grown historically to a good extend), so please be critical.
- When I log into a system (nowadays via the graphical X login), there might be some tasks which should run once, e.g. establish a connection to some kind of server, present me a the today's todo list, autostart some commands, etc. This shouldn't happed every time I open up a new terminal. So there's a set of config files (
/etc/profile
, ~/.bash_login
and so on, refer to the manual for an accurate list) sourced only by login shells.
- Accordingly, to close the connections, kill some programs, run a backup script there is
~/.bash_logout
when the login shell exists.
- so, the "normal" shell I use in a terminal, shouldn't ba a login shell, but nevertheless should read my personal preferences from
~/.bashrc
, because I want my keybindings to interact with the shell -- hence this is an interactive, non-login shell.
- and last, but not least when bash is used for scripting, neither of this is important.
bash
should start as fast as it can, i.e. shouldn't read any config files. This is a non-interactive, non-login shell.
So, my answer to your question What would we lose if we only had one type of shell? is in one word: "Flexibility."
The answer to your second question is easy:
$-
lists the current set of options. These can either be set by command line parameters to bash
or via the set
builtin. So you have to look at two places in the manual:
OPTIONS
section:
-i If the -i option is present, the shell is interactive.
SHELL BUILTIN COMMANDS
section, subsection set
:
-h Remember the location of commands as they are looked up for execution. This is enabled by default.
-m Monitor mode. Job control is enabled. This option is on by default for interactive shells on systems that sup‐
port it (see JOB CONTROL above). Background processes run in a separate process group and a line containing
their exit status is printed upon their completion.
-B The shell performs brace expansion (see Brace Expansion above). This is on by default.
-H Enable ! style history substitution. This option is on by default when the shell is interactive.
Best Answer
If you SSH into your Ubuntu box, you're getting an interactive login shell. Here's the difference:
Interactive vs. non-interactive: Any shell where you can type at a prompt is interactive. In fact, many scripts test for the variable
$PS1
which holds the prompt string to find out whether they're interactive. If a shell is executing a shell script, it's non-interactive.So, if you do
ssh yourbox.example.com
, you'll get an interactive shell, asuming default settings, while if you dossh yourbox.example.com mighty_shellscript.sh
, you'll end up with a non-interactive shell and your SSH session will terminate when the script terminates.Login vs. non-login: When you log in from the console or remotely (such as SSH), or when you pass the
-l
option tobash
, you get a login shell. Otherwise--such as when you open up a terminal window--you get a non-login shell.To test whether a shell is a login shell, check whether its command name is
-bash
instead ofbash
: