Bash and Its Startup File Execution Algorithm

Table of contents

Bash and Its Startup File Execution Algorithm
Execution order
Consequences
Files

Bash and Its Startup File Execution Algorithm

Execution order

A login shell is one whose first character of argument zero is a -, or one started with the --login option.

An interactive shell is one started without non-option arguments and without the -c option whose standard input and error are both connected to terminals (as determined by isatty(3) ), or one started with the -i option. PS1 is set and $- includes i if bash is interactive, allowing a shell script or a startup file to test this state.

o Interactive shells

When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, 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. The first 2 files do not exist in my setup, so it runs ~/.profile.

When a login shell exits, bash reads and executes commands from the file ~/.bash_logout, if it exists.

When an interactive shell that is not a login shell is started, bash reads and executes commands from /etc/bash.bashrc and ~/.bashrc, if these files exist.

This may be inhibited by using the --norc option. The --rcfile file option will force bash to read and execute commands from file instead of /etc/bash.bashrc and ~/.bashrc.

        Files run ...      If ...
        1st: /etc/profile  Interactive login shell
        2nd: ~/.profile
        3rd: ~/.bashrc     Interactive non-login shell
o Non-interactive shells

When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute.

Thus, bash behaves as if the following command were executed:

        if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

but the value of the PATH variable is not used to search for the file name.

Given a shell script like:

        #!/bin/bash

        . ~/.profile
        . ~/.bashrc

        echo Hi

Bash will run ~/.profile, but when it runs ~/.bashrc, it hits this at the top:

        # If not running interactively, don't do anything
        [ -z "$PS1" ] && return

which means ~/.bashrc does nothing. This in turn means ~/.bash_aliases and /home/ron/perl5/perlbrew/etc/bashrc are not run.

In my setup, ~/.profile also sources ~/.bashrc, but that too does nothing.

Consequences

If you want to set $LD_LIBRARY_PATH (say to use Perl's BerkeleyDB), or $PATH (say to add ~/bin or use Oracle's BerkeleyDB programs), you should do this in ~/.profile. This makes the changes available even when ~/.bashrc does not run.

Files

o ~/.bash_aliases

Executed by ~/.bashrc.

o ~/.bash_login

Executed by bash for login shells. This file is not read by bash, if ~/.bash_profile exists. ~/.bash_login does not exist in my setup. Neither does ~/.bash_profile.

o ~/.bash_logout

Executed by bash when login shell exits. This file does not exist in my setup.

o ~/.bash_profile

Executed by bash for login shells. This file does not exist in my setup.

o ~/.bashrc

Executed by bash for non-login shells. E.g. run by /usr/bin/gnome-terminal. Also, in my setup, ~/.profile runs ~/.bashrc.

o /etc/bash.bashrc

Executed by bash for non-login shells.

o /etc/profile

Executed by bash for login shells.

o /home/ron/perl5/perlbrew/etc/bashrc

Executed by ~/.bashrc.

o ~/.profile

Executed by bash for login shells. This file is not read by bash, if ~/.bash_profile or ~/.bash_login exists. The latter 2 files do not exist in my setup, so it runs ~/.profile. E.g. run by /usr/bin/xterm. Also, in my setup, ~/.profile runs ~/.bashrc.