BASH Basics: Introduction to BASH

What happens at startup and login with variables and BASH, and how can I customize the BASH prompt and BASH behavior? After looking at a lot of essential commands, it's time to do something fun. When we want to live on the command line, it's a good idea to shape it to our needs. For this, we first need to look at what is done by BASH when a user logs in or BASH starts by invoking a script.

BASH invoked as an interactive login shell

This is the usual case when you log into the system via ssh, or have a terminal open without a graphical UI. When BASH is invoked as an interactive login shell, it first reads and executes commands from the following files:

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

/etc/profile calls /etc/bash.bashrc, so there is one more to add to the list. But ~/.profile starts also ~/.bashrc, so this is the place we need to look at for all the interactive shells. When an interactive login shell exits, or a non-interactive login shell executes the exit builtin command, Bash reads and executes commands from the file ~/.bash_logout, if it exists.

Invoked as an interactive non-login shell

When you have a graphical UI and open a terminal application like mate-terminal or xterm, a non-login shell gets executed. When an interactive shell that is not a login shell is started, BASH reads and executes commands from ~/.bashrc, if that file exists. The --rcfile file option will force BASH to read and execute commands from file instead of ~/.bashrc.

Invoked non-interactively

For the sake of completeness, this is what happens when you run a script with BASH. 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.

For our use cases, it is ~/.bashrc which is the most important, since it deals with all the interactive BASH shells. If you want something to run only once after login, put it in /.profile instead. ~/bash_profile could also be used, but doesn't exist on Ubuntu.

Examples for both would be adding a function to ~/.bashrc, since you want to have it available everytime:

### shows last installed packages from history
function apt-history(){

zcat -qf /var/log/apt/history.log* | grep -Po '^Commandline: apt install (?!.*--reinstall)\K.*'
For the other option, adding something like the following to the path via ~/.profile, which you want only once for a login:
$ export PATH="$PATH:/some/addition"
This avoids a path which has :/some/addition tacked on every time BASH is called. If you want to see everything that happens with BASH and these files put together, you can try:
$ PS4='+ $BASH_SOURCE:$LINENO:' BASH_XTRACEFD=7 bash -xlic "" 7>&2
However, don't be surprised by the volume of it, and don't forget to exit again.

Changing the BASH prompt

Now it's time to put this into practice. While the colored standard prompt is nice, it might be better to have it tailored to your liking. Go to and play with the different options.

Figure 1 - bashrc generator
Figure 1 - bashrc generator

(Figure 1 - bashrc generator)

After you dragged the interesting elements into box #2, you'll notice that there's a lot of escape code in box #4. This is how BASH can interpret different variables and colors. The principle is similar to Unicode or HTML coded as plain ASCII, just with colors and screen properties.

Modern terminals like mate-terminal or xterm are capable of 256 colors. To see them, save the following script as, make it executable with chmod a+x and run it:


for fgbg in 38 48 ; do # Foreground / Background
for color in {0..255} ; do # Colors
# Display the color
printf "\e[${fgbg};5;%sm %3s \e[0m" $color $color
# Display 6 colors per lines
if [ $((($color + 1) % 6)) == 4 ] ; then
echo # New line
echo # New line

exit 0
This is what your terminal is capable of. Now on the site, you can double-click the elements in box #2 for different colors and boldness. The escape codes are generated in box #4. After you find a version you like, copy the code from box #4 and test it in your BASH window by pasting it and pressing return. If you are satisfied, open ~/.bashrc with a text editor, search for the line starting with PS1= and replace it with the line from box #4, but without the export part!

Personally, I like to keep a balance between keeping it short, simple and unobtrusive, and having dashboard-like information in the prompt:

Figure 2 - command prompt with PS1 example
Figure 2 - command prompt with PS1 example

As you can see, the root prompt differs from the user prompt to remind me that I have root power and can potentially destroy my system when I am careless. If you also want to have a prompt like this, looks for the following line:

if [ "$color_prompt" = yes ]; then
Add the following code immediately after the above line:
if [ $(id -u) -eq 0 ];
then # you are root, make the prompt red
PS1='${debian_chroot:+($debian_chroot)}\[\e[00;33m\]\u\[\e[00m\]@\[\e[00;34m\]\h\[\e[00m\]:\[\e[00;36m\]\w\[\e[00m\]\e[01;31m#\e[00m '
PS1='${debian_chroot:+($debian_chroot)}\[\e[00;32m\]\u\[\e[00m\]@\[\e[00;34m\]\h\[\e[00m\]:\[\e[00;36m\]\w\[\e[00m\]$ '
Replace everything before the non-indented else statement a few lines down. Now with the shiny new prompt, we want to do more. What else can you do to customize your BASH experience?

BASH Functions

As briefly mentioned above, you can put functions into the ~/.bashrc file. The example apt-history is a function which shows the last installed or removed packages. After you have changed the ~/.bashrc, don't forget to log out and log in again to have your changes recognized! Just give the function a name, start with function functionname() and put your code between curly brackets.

Another fun example would be to get the current weather in the console. You can get a current weather report in the terminal by doing curl, with the two-letter language prefix like you can get a weather report for Paris in French.

To see all the options, type the following command:

$ curl

It is annoying to always type all the desired options; with a function, you can skip all that and just type “wttr” to get the current weather for your location, in the right language and all the options you want:

function wttr()
# Seoul is the default location
curl -H "Accept-Language: ${LANG%_*}""${1:-Seoul}"
For ODROID usage (ie: XU4), it might be convenient to have a function cputemp, where you can run cputemp and get the cpu temperature with the following function:
function cputemp()
#for XU4 usage, others may differ
cat /sys/devices/virtual/thermal/thermal_zone0/temp
This gives the temperature in °C with three trailing zeros at the end. For a prettier output, a script would be better suited to not overload the ~/.bashrc. You can add all your functions at the end of the ~/.bashrc file, one after the other.

BASH aliases

You may have noticed in an earlier part of the series that you can call “ll” to get “ls -l” in Ubuntu. For similar aliases which tailor the commands to your need, make a new file ~/.bash_aliases and enter lines with the commands and their standard options you want to use:

$ alias ping='ping -c 5'
for example stops the ping command after a count of 5 pings, similar to the operation of ping in Windows. Another example would be to always get the human-readable form if you want to see how much space is free on the disks:
$ alias df='df -h'
In the next part, we look at an introduction to scripting: variables, tests, loops. The one-liner for making archives out of different folders from the last chapter was a glimpse of things to come. With more complex requirements, our BASH executables won't fit in one line anymore; now it's time for writing real scripts.


Be the first to comment

Leave a Reply