Why is /etc/profile not invoked for non-login shells?
Login and non-login shell defined as:
su - $USER # will give you a login shell
bash # will give you a non-login shell
/etc/profile is not invoked for non-login shells, such as when you start konsole (kde). /etc/profile is only invoked for login shells.
Why is that? Please explain, because I like to understand the rationale of this.
Solution 1:
/etc/profile
is invoked only for login shells because that is its specific purpose.
If you want a command to run for interactive shells that are not login shells, and you're using bash
, put it in ~/.bashrc
or /etc/bash.bashrc
.
The purpose of the "profile" files is to contain commands that ought to be run for login shells only. These files are:
/etc/profile
, run by all Bourne-compatible shells (includingbash
anddash
) when started as a login shell.-
Scripts in
/etc/profile.d
.This is for Bourne-style shells, but it's not coded into the shell executable itself. Rather, commands in
/etc/profile
calls them. For example, on my Ubuntu 12.04 system,/etc/profile
includes these lines:if [ -d /etc/profile.d ]; then for i in /etc/profile.d/*.sh; do if [ -r $i ]; then . $i fi done unset i fi
.profile
in the user's home directory, run by Bourne-compatible shells when started as a login shell (unless overridden, see below).-
.bash_profile
or.bash_login
in the user's home directory. These are ignored by shells other thanbash
. But if.bash_profile
exists,bash
runs it instead of.profile
. If.bash_profile
doesn't exist but.bash_login
exists, that is run instead of.profile
.(But it is common for
.bash_profile
or.bash_login
, when it exists, to be written so as to *explicitly call.profile
.)The benefit of shell-specific profile files is that they can contain commands or syntax that are only valid for that shell. For example, I can use the
[[
evaluation operator in.bash_profile
/.bash_login
but if I use it in.profile
and then log in withdash
as my shell, it will fail.
What Should Go In "profile" Files
"profile" files should contain commands that ought only run once, at the beginning of login. (This includes graphical logins, as they start with a login shell, too.) If a shell is interactive, the user running it is probably logged on, and so it probably has an ancestor (that started it, or started what started it, or started that, etc.) that was a login shell.
You might want to run a command only once because:
- there is no reason to run it more than one time per login, it would be inefficient, or
- it would produce an undesired result, to run it more than once per login.
As an example of the second situation, where an undesirable result would occur, consider these lines, which appear by default in every user's ~/.profile
:
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
Suppose you SSH'd in, ran another shell (say, zsh
), at some point found you wanted to temporarily go back to bash
but keep your environment (so ran bash
again while in zsh
), and then ran a program like mc
that runs a shell as part of its interface. If bin
exists in your home folder and your username is james
, your PATH
in the innermost shell is something like:
/home/james/bin:/home/james/bin:/home/james/bin:/home/james/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
That's inefficient and (much more importantly) makes it hard to understand the contents of PATH
.
This is by no means a disaster, though. As far as I can tell, if every interactive shell sourced "profile" files, nothing terrible would happen, in the default configuration. However, since the purpose of "profile" files is to contain commands to just run once per login, a user or administrator may add commands to a profile that must only run when starting a login shell.
Where to Put Commands for Every Interactive Shell to Run
If you are using bash
, there are files for commands that are to be run in every interactive shell:
/etc/bash.bashrc
-
.bashrc
in the user's home directory.
This is most commonly used for commands that
- affect only the environment of the shell in which they run--not even child shells, or
- ought to run even when this is not the login shell.
For example, command-line tab-completion should generally be enabled whether or not bash
was the login shell. So this appears in ~/.bashrc
:
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi
There, 1 and 2 both apply: this does not carry over to other shells run inside this one, and tab-completion should work in bash
even if I logged in with a different shell.
Where to Put Commands for Login Shells and Interactive non-Login Shells
If you're using bash
and want a command to run in login shells and interactive shells and that are not login shells, it is generally sufficient to put it in /etc/bash.bashrc
or ~/.bashrc
. This is because, by default, /etc/profile
and ~/.profile
run them explicitly. For example, ~/.profile
has:
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
(Similarly, /etc/profile
sources /etc/bash.bashrc
for bash
.)
Thus both "profile" and "rc" files run when you start an interactive bash
shell (whether or not it's a login shell).
Where to Put Commands to Run in non-Interactive Shells
You probably do not want to specify any commands for all non-interactive shells to run; they would run every time a script is run (provided the script is run by the shell you configure to run them).
This can cause substantial breakage. If you're going to do this, and there is not an administrator account on the system besides the one you're using, you might want to create one; that can make it easier to fix mistakes.
In bash
, the "rc" files are actually run whether the shell is interactive or not. However, at the top they say:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
So, if you need commands to run automatically even in non-interactive shells like the ones that run to execute scripts, you can add your commands before those lines.
Starting a Login Shell
Logging in starts a login shell. If you want a shell started after that to behave as a login shell, start it with the -l
flag (stands for login). For example:
sh -l
bash -l
pdksh -l
That's the best way to start a login shell (without logging in) unless you want to start one as another user. Then, use:
-
sudo -i
forroot
(usesudo -s
for a non-login, interactive root shell) -
sudo -u username -i
for any user -
su - username
for non-root
users (usesu username
for a non-login, interactive root shell)
What's an initial login shell?
An initial login shell is the same as a login shell. Everywhere this answer says "login shell" it could say "inital login shell" (except in this section, which would already have stoped making sense).
One reason for the term inital login shell is that login shell is also used in a different sense--to identify which program is used as the shell that is executed by logging on. This is the sense of login shell used to say:
- "OpenBSD's default login shell is
ksh
; in Ubuntu, it'sbash
." - "You can change your login shell with
chsh
."
Further Reading
- "Configuration files for shells" in "Unix shell" (Wikipedia)
-
bash
manpage - Full bash manual (GNU)