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.
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
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