Running Bash in detail

If you found this page in a search, you are probably trying to solve some kind of bash startup problem.

Perhaps your bash environment is not setting an environment variable and you don't understand why. You may have stuck something in various bash boot files or profiles or all files at random until it worked.

In any case, the point of this post is to make bash startup as simple as possible so that you can deal with problems.

Diagram

This flowchart summarizes all the processes when bash starts up.

Running Bash in detail

Now let's take a closer look at each part.

login shell?

First you need to choose whether you are in the login shell or not.

The login shell is the first shell you enter when you log in to an interactive session. The login shell does not require a username and password. You can force a login shell to start by adding the flag --login when called bash, For example:

bash --login

The login shell sets up the base environment the first time you start the bash shell.

Interactive?

Then you determine whether the shell is interactive or not.

This can be checked by the presence of a variable PS1 (it sets the command input function):

if [ "${PS1-}" ]; then echo interactive else echo non-interactive fi

Or see if the option is set -i, using a special hyphen variable - in bash, for example:

$echo $-

If there is a symbol in the output i, then the shell is interactive.

In a login shell?

If you are in a login shell, then bash looks for the file /etc/profile and runs if it exists.

It then searches for any of these three files in the following order:

~/.bash_profile ~/.bash_login ~/.profile

When it finds one, it launches it and skips the others.

In an interactive shell?

If you are in an interactive non-login shell, it is assumed that you have already been in a login shell, the environment is set up and will be inherited.

In this case, the following two files are executed in order, if they exist:

/etc/bash.bashrc ~/.bashrc

No option?

If you are neither in a login shell nor in an interactive shell, then your environment will indeed be empty. This causes a lot of confusion (see below for cron jobs).

In this case, bash looks at the variable BASH_ENV your environment and creates the appropriate file that is specified there.

Typical difficulties and rules of thumb

cron jobs

95% of my bash startup debugging is due to a cron job not working as expected.

This damn task works fine when I run it from the command line, but fails when I run it from crontab.

Here two reasons:

  • cron jobs are not interactive.
  • Unlike command line scripting, cron jobs do not inherit a shell environment.

You usually don't notice or care that a shell script is not interactive because the environment is inherited from the interactive shell. This means that everything PATH и alias configured as you would expect.

That is why it is often necessary to establish a specific PATH for a cron task like this:

* * * * * PATH=${PATH}:/path/to/my/program/folder myprogram

Scripts calling each other

Another common problem is when scripts are mistakenly set to call each other. For example, /etc/profile appeals to ~/.bashrc.

This usually happens when someone tried to fix some kind of error and everything seemed to work. Unfortunately, when it comes to separating these different types of sessions, new problems arise.

Docker image in sandbox

To experiment with shell startup, I created a Docker image that can be used to debug shell startup in a secure environment.

Run:

$ docker run -n bs -d imiell/bash_startup
$ docker exec -ti bs bash

Dockerfile is located here.

To force a login and simulate a login shell:

$ bash --login

To test a set of variables BASH_ENV:

$ env | grep BASH_ENV

For debugging crontab a simple script will be executed every minute (in /root/ascript):

$ crontab -l
$ cat /var/log/script.log

Source: habr.com

Add a comment