Skip to Content

BASH Environment and Shell Variables (Complete Guide)

BASH Environment and Shell Variables (Complete Guide)

Variables provide a simple way to share configuration settings between multiple applications and processes in Linux, and are mainly set in either a terminal or shell configuration file upon start up.

They are either environmental or shell variables by convention. Both of which are usually defined using all capital letters. This helps users distinguish environmental variables from within other contexts.


1 – Terminology

As said there are technically one of two categories a variable can fall into:

“Environment variables” have been defined for use in the current shell and will be inherited by any child shells or processes spawned as a result of the parent. Environmental variables can also be used to pass information into processes that are spawned by the shell.

“Shell variables” are contained exclusively within the shell in which they were set or defined. They are mostly used to keep track of ephemeral temporal data, like the current working directory in a session.

2 – Displaying Variables

To see all currently set environment variables in a terminal type:

[alert-announce]

  1. $ printenv

[/alert-announce]

Alternatively the shorter command env works too:

[alert-announce]

  1. $ env

[/alert-announce]

To see an individual or specific environment variables and print with standard output use either of the following:

[alert-announce]

  1. $ printenv TERM

[/alert-announce]

Prints multiple variables.

[alert-announce]

  1. $ printenv SHELL USER

[/alert-announce]

echo prints contents.

[alert-announce]

  1. $ echo $TERM

[/alert-announce]

Which can print multiple variables too.

[alert-announce]

  1. $ echo $LANG $HOME

[/alert-announce]

To output shell variables as well as environment variables using set do the following:

[alert-announce]

  1. $ set | less -N

[/alert-announce]

set is usually used to change or unset shell options and parameters but here we have piped the command through less to see what it outputs instead of allowing it to make changes.

The command can be modified to not show the residual bash functions included in the last output (using posix mode). The brackets also indicate that the process will be run in a sub shell so that set does not actually change anything in the current shell’s environment.

[alert-announce]

  1. $ (set -o posix; set) | less -N

[/alert-announce]

Note that there is no one command for retrieving only what we class as shell variables. One way of getting these as output is with a sorted comparison from both of the two previous set and env commands. This is not one hundred percent accurate, however.

[alert-announce]

  1. $ comm -23 <(set -o posix; set | sort) <(env | sort) | less -N

[/alert-announce]

In the last command comm is used to compare the output of set in a sub shell with the output of env in a sub shell, before finally being fed through less . The two compared outputs are also sorted with sort .


3 – Variable Definitions

Environment Variables

SHELL – /bin/bash

This is how the system knows what shell to be used when interpreting commands. In most Linux systems Bash is the default primary shell, but many others can be installed on the system and assigned to this variable.


TERM – xterm

This specifies the type of terminal to emulate when running the shell. The default in GUI based desktop environments is often linux or xterm .


USER – scarlz

Is set to the username of the currently logged in Linux user.


PWD – /etc/apache2

Like the pwd command it contains the currently active working directory.


OLDPWD – /home/scarlz/dotfiles

The last working directory the user moved from. The shell uses this when the cd - command is invoked.


LS_COLORS – *.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:

The ls command has built-in colour support used to differentiate between file types and folders. Colour codes are stored in this variable that determine the colours used.


PATH – /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

The shell’s main “Path” variable holds a list of directories that the system will query when looking for commands/programs the user types in. They are checked in the order listed.


LANG – en_GB.UTF-8

The currently set language and localization in use (locales), including character encoding.


HOME – /home/scarlz

The current user’s home directory.


_ – /usr/bin/printenv

The previously executed command and its path.


EDITOR – vim

The shell’s preferred text editor.


PAGER – more

The shell’s preferred pager program.


MAIL – /var/spool/mail/$LOGNAME

Contains the location of incoming email. The traditional path is used as an example here.


Shell Variables

BASHOPTS

The list of options that the shell included when bash was run. Useful for finding out if the shell environment currently can do what you expect it to.

[alert-announce]

  1. $ echo $BASHOPTS
  2. BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob

[/alert-announce]

BASH_VERSION

The version of bash being executed, in human-readable form.

[alert-announce]

  1. $ echo $BASH_VERSION
  2. 4.3.11(1)-release

[/alert-announce]

BASH_VERSINFO

Similar to the last variable except in “machine“ readable format.

[alert-announce]

  1. $ echo $BASH_VERSINFO
  2. 4

[/alert-announce]

COLUMNS

The number of columns that are being used to draw output to the screen.

[alert-announce]

  1. $ echo $COLUMNS
  2. 239

[/alert-announce]

DIRSTACK

The stack of directories that are available with the pushd and popd commands.

[alert-announce]

  1. $ echo $DIRSTACK
  2. ~

[/alert-announce]

HISTFILESIZE

Number of lines of command history that gets stored to the file per bash session.

[alert-announce]

  1. $ echo $HISTFILESIZE
  2. 2000

[/alert-announce]

HISTSIZE

The number of lines of command history maximum to be stored in memory.

[alert-announce]

  1. $ echo $HISTSIZE
  2. 1000

[/alert-announce]

HOSTNAME

The hostname of the computer at this time.

[alert-announce]

  1. $ echo $HOSTNAME
  2. scarlz-corsair

[/alert-announce]

IFS

The internal field separator character that separates input on the command line. By default, this is a space so there is no real output to show as an example command.


PS1

The primary command prompt’s definition. Defines quint-essentially what your prompt looks like when you start a shell session.

[alert-announce]

  1. $ echo $PS1
  2. \[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$

[/alert-announce]

SHELLOPTS

Any shell options that can be or have been set with the set option.

[alert-announce]

  1. $ echo $SHELLOPTS
  2. braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor

[/alert-announce]

UID

The assigned UID of the current user.

[alert-announce]

  1. $ echo $UID
  2. 1000

[/alert-announce]

4 – Setting Variables

Shell Variables

To create a shell variable in the current shell session, specify a name and a value in the same manner as usual in Bash. Adhering to the naming convention of using full capitals for the variable name.

[alert-announce]

  1. $ EXAMPLE_VAR=’hello world!’

[/alert-announce]

Note the single quotation marks used since the string content of our variable contains a space.

Also when special characters like ! are used in the string, apostrophes must be inserted instead of double quotes to enclose the the string.

! is special character in Bash as it is usually used to expand the shell history.

We can see the newly defined variable by using echo :

[alert-announce]

  1. $ echo $EXAMPLE_VAR
  2. hello world!

[/alert-announce]

As said this is only a shell variable within the current Bash session and not an environmental variable.

This can be checked by using printenv :

[alert-announce]

  1. $ printenv EXAMPLE_VAR
  2. hello world!

[/alert-announce]

No output is returned as the definition is not recognised as part of the environment.

Let’s take this as an opportunity to demonstrate a way of accessing the value of any shell or environmental variable.

Remember like in these example that to reference the value of a variable, precede it with a $ sign. This is so the shell knows to substitute the name of the variable for it’s content.

Environment Variables

To create one, export an existing shell variable into the shell’s persistent environment using the export command:

[alert-announce]

  1. $ export EXAMPLE_VAR

[/alert-announce]

This time when we check the variable with printenv it will output.

[alert-announce]

  1. $ printenv EXAMPLE_VAR
  2. hello world!

[/alert-announce]

The variable now descends into a sub shell child process and is retained from the parent, test this by starting anew shell session with bash :

[alert-announce]

  1. $ bash
  2. $ echo $EXAMPLE_VAR
  3. hello world!

[/alert-announce]

To bypass having to set a variable and then export it to the environment, the process can be combined like this:

[alert-announce]

  1. $ export INSTANT_ENV_VAR=”instant definition plus export!”

[/alert-announce]

Return to the parent shell we came from with exit , and try to echo the previously exported variable:

[alert-announce]

  1. $ exit
  2. $ echo $INSTANT_ENV_VAR

[/alert-announce]

Notice no output is returned as environment variables can only be passed to child processes, and not the other way around. This is sensible for the most part as it “prevents programs from affecting the operating environment from which they were called”.

Also when you exit back into your main parent shell, the child shell environment is destroyed.


5 – Demoting and Unsetting Variables

To change an already set environment variable back into a lesser shell variable use the -n parameter with export :

[alert-announce]

  1. $ export -n EXAMPLE_VAR

[/alert-announce]

Now nothing is returned when using printenv on the variable:

[alert-announce]

  1. $ printenv EXAMPLE_VAR

[/alert-announce]

It’s still set as a shell variable so to undefine it completely from this local shell session you can use:

[alert-announce]

  1. $ unset EXAMPLE_VAR

[/alert-announce]

6 – Persistent Variables

To create predefined variables at login depends upon how bash is started and which configuration file it uses to do so. The deciding factors on which file is used relies on the types of “login shell” that have being initiated by the user.

The types being either:

  • Login or Non-Login
  • Interactive or Non-Interactive

So the two distinctions that are taken into account are whether the shell is being spawned as a “login” or “non-login” session. As well as whether the session is either an “interactive session” or “non-interactive” session.

Login

A login shell is a shell session that always begins by authenticating the user. If you are signing into a terminal session or through SSH and authenticate, your shell session will be classed and set as a “login” shell.

A session started as a login session will read configuration details from the /etc/profile file first, and then look for the first login shell configuration file it can find in the user’s home directory. In order to get user-specific configuration details.

These files are the first it can find out of ~/.bash_profile , ~/.bash_login , and ~/.profile .


Non-Login

If you start a new shell session from within your authenticated session, like earlier when we called the bash command from the terminal, a non-login shell session is started. This is as you were were not asked for any authentication details when you started the child shell.

A session defined as a non-login shell will always read /etc/bash.bashrc and then the user-specific ~/.bashrc file to help build its environment.


Interactive

An interactive shell session is a shell session that is attached to a terminal and in use. So a normal session that begins with SSH is usually defined as an interactive login shell. See “Non Interactive” in the next section to see the difference between the two.


Non-Interactive

A non-interactive shell session is one that is not attached to a terminal session, and not currently in use. For example a script run from the command line is usually run in a non-interactive, non-login shell.

Most notable non-interactive shells read the environment variable named BASH_ENV and read the file specified in this variable to construct the new shell environment.


Setting Environment Variables at Login

So there are a variety of circumstances that dictate which of the different files are needed to set predefined variables.

This has it’s advantages and gives a lot of flexibility for specific situations where you might want only certain settings for a login shell, and other different settings in a non-login shell.

Despite this to make things easier and more general, most people most of the time will want the same settings for both scenarios.

Depending upon your Linux distribution and personal setup, usually the login configuration files source the non-login configuration files. Meaning that you don’t have to define the variables in both files and can get away with defining environment variables that you want in both only inside the non-login configuration files. They will then be read in both scenarios as they’re sourced in the latter.

It’s also best to set them for your individual user and not system wide. so to make them available to both login and non-login shell sessions define these variables in the ~/.bashrc .

An example of the line to set a persistent environment variable in the .bashrc file would look like this:

[alert-announce]

.bashrc

  1. $ export EXAMPLE_VAR=’hello world!’

[/alert-announce]

Which is the same as before whilst on the command line.

The next time you start a shell session, your environment variable declaration(s) are always read and passed on to the shell’s environment (including subsequent child shells too).

You can force your current session to read the config file at any time by typing in a terminal:

[alert-announce]

  1. $ source ~/.bashrc

[/alert-announce]

To set them in the system wide files if you prefer, do the same except add the variable definition(s) to: /etc/profile , /etc/bash.bashrc , or /etc/environment instead.