Baeldung Pro – Linux – NPI EA (cat = Baeldung on Linux)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

1. Overview

When working with Linux systems, we may encounter shell initialization files like /etc/profile, ~/.bash_profile, ~/.bashrc, and more. One common point of confusion always is why the /etc/profile is not invoked for non-login shells. To understand this, let’s examine how the shell initialization process works.

In this tutorial, we’ll discuss it along with the distinction between login and non-login shells and the specific role of /etc/profile.

2. Understanding Shells: Login vs. Non-Login

A login shell is the shell session we enter when we log in to a system. For example, logging in through a terminal by SSH or by switching to another user using a su – username. It’s a login shell also if it starts with a – as the first character, let’s say -bash.

A non-login shell, on the contrary, is typically started without requiring the user to log in again. Examples include opening a new terminal window after logging in, running a script with Bash, or starting a new shell instance from an already active terminal. Non-login shells do not require the user to authenticate again.

3. What is /etc/profile?

Operating systems use system-wide configuration file /etc/profile to set up environment variables and shell settings. It’s read by the shell for every user when the OS initiates a login shell. This file ensures that global settings, such as PATH or environment variables, are set consistently for all users.

The main reason why the /etc/profile is not invoked for non-login shells is how shell initialization is designed. The shell initialization process differentiates between login and non-login shells. It aims to load only the necessary configurations to avoid redundancy and improve efficiency.

Let’s see a breakdown of how initialization works.

3.1. For Login Shells

When the OS initiates a login shell, the shell goes through a specific sequence of configuration files to set up the environment. This sequence ensures that the system-wide and user-specific settings work for a Bourne-compatible shell like bash. Let’s discuss in detail the breakdown of the process.

The /etc/profile file contains system-wide environment settings, including variables like $PATH, global aliases, and default shell options. The shell reads the /etc/profile first when any login shell starts. This file sets up the environment for all users on the system, making it useful for settings that should apply universally. Other Typical contents include Limits on resources (e.g., ulimit settings) and running scripts or commands for every user:

# Add /usr/local/bin to the PATH for all users
if [ -d /usr/local/bin ]; then
    PATH="$PATH:/usr/local/bin"
fi
export PATH

After reading the /etc/profile, the shell looks for ~/.bash_profile (located in the user’s home directory, e.g., /home/rahul/.bash_profile). The shell reads this only if it exists. It allows individual users to customize their environment variables, aliases, and startup programs for their shell session.  The ~/.bash_profile file is user-specific. Other typical content of this file includes loading configuration files like ~/.bashrc:

# Set user-specific PATH
PATH="$HOME/bin:$PATH"
# Source .bashrc if it exists
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi
export PATH

The inclusion of ~/.bashrc is typical because the OS executes ~/.bash_profile only for login shells, while it sources ~/.bashrc for non-login interactive shells. By including .bashrc in the .bash_profile, we ensure that the OS also loads our interactive shell settings for login shells.

If ~/.bash_profile does not exist, the shell checks for ~/.bash_login as an alternative. However, the OS rarely uses this file, and many users prefer to use ~/.bash_profile directly. Similar to ~/.bash_profile, this file contains user-specific environment settings. So, it’s simply an alternative for users who might not have a ~/.bash_profile.

If neither ~/.bash_profile nor ~/.bash_login is present, the shell will look for ~/.profile. This file is a more generic configuration file and is compatible with other shells, like sh and dash. The users use this file when they do not have shell-specific configurations in place. Therefore, this file is less specialized but still allows users to configure their environment:

# User-specific PATH
if [ -d "$HOME/bin" ]; then
    PATH="$HOME/bin:$PATH"
fi
export PATH

3.2. For Non-Login Shells

When a non-login shell starts, it only reads the ~/.bashrc file (user-specific configuration). The non-login shells skip the /etc/profile since their primary use is to set up the environment at login. Reloading it every time a new non-login shell starts, would be redundant.

The reason behind this behavior is that the initialization settings in the /etc/profile would typically configure the environment for the user’s entire session. Once this setup is complete in a login shell, it’s usually unnecessary to repeat it for every new shell invocation within that session.

4. The Role of ~/.bashrc in Non-Login Shells

Users rely on the ~/.bashrc file to handle configurations for non-login shells. This file sets up aliases, functions, and other interactive shell customizations for non-login shells.

To ensure consistency across all shell types, many users include the following snippet in their ~/.bash_profile file to source ~/.bashrc in login shells as well:

if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

This approach ensures that login and non-login shells share the same environment settings, effectively bridging the gap between the two.

5. Conclusion

In this article, we understood the reason why the /etc/profile is not invoked for non-login shells. We learned how it’s a key design choice that helps streamline shell initialization and avoid unnecessary loading of configuration files. We also discussed the distinction between login and non-login shells.

By understanding this difference, system administrators and users can better manage their shell environments. This in turn ensures optimal performance and consistent behavior across all shell instances. Hence, we learned to apply specific configurations to all shell types e.g. by sourcing ~/.bashrc from ~/.bash_profile to achieve a unified environment.