Last updated:

The Linux environment variables, Bash environment variables, and Shell specials variables allow us to pass information between commands and subprocesses, or control some of the shell behavior. This post covers an extensive list of special and environment variables used by the Bash shell as well as how to define and use custom environment variables.

What Are The Environment Variables?

The Environment Variables form a simple and effective way to pass information about the current operating environment to the program being executed.

When a program or command is being executed, it is being passed an array of strings called the environment. This array contains key/value pairs in the form of key=value. Each of the key/value pair is considered an environment variable and becomes accessible to the executed command or program. There are different ways for the shell to mark a variable for export to the environment variables. In Bash, the preferred way will be to use the declare -x command.

Two common examples of Linux environment variables are the $PATH and $HOME variables.

The environment variables may be modified temporarily by prefixing a command with a key=value parameter assignment syntax. The environment variables aimed to be used by the shell or a POSIX utility command should conform to the POSIX.1-2017 naming convention with a variable name consisting only of uppercase letters, digits, and the underscore _ but cannot begin with a digit. Uppercase and lowercase environment variables represent different variables. Lowercase environment variables are reserved for the application’s specific use and are never used by POSIX utilities.

For example, TZ=UTC date and tz=UTC date are two different commands with only the first notation passing the timezone information to the POSIX date utility. When using a custom non-POSIX application, the notation TZ=UTC myApp and tz=UTC myApp may both be valid and the use of the tz environment variable will be implementation-specific.

Environment variables are often configured or augmented in a shell startup script like the .bashrc file in Bash.

What Are The Specials Shell Variables?

The shell special variables are only accessible to the shell execution environment, possess special properties, and may be updated as the shell process commands. Those variables are often confused with environment variables while they are not exported variables and are limited to the current instance of the shell. The Bash only special variables are usually named with the prefix BASH_ like the BASH_VERSION variable. Some other standard POSIX shell variables will just be handled specifically and attributed special value by Bash.

How to Set and Unset Environment Variables?

There are multiple ways to manipulate the environment variables in a Bash shell.

The declare builtin

The export builtin

The unset builtin

The printenv command or builtin

⚠️ The printenv may be a command or sometimes a shell builtin. It may not be always available in your environment.

The set builtin

⚠️ The set builtin, despite its name, cannot be used to set/declare an environment variable. It can only print existing variables or set and unset shell specific options or shell positional parameters.

The env command

List Of Special And Environment Variables in Bash

Some of the Bash Shell special and environment variables are described in separate sections of this site.

The other Bash special and environment variables can be found below.

The User Home Directory Variable: HOME

The $HOME environment variable contains the current user’s home directory. The cd builtin command uses the $HOME variable as default when used with no parameters. The value of this variable is also used by the tilde expansion.

[me@linux /usr]$ cd
[me@linux ~]$ pwd
[me@linux ~]$ echo $HOME ~
/home/jdoe /home/jdoe

Filename Expansion Variable: GLOBIGNORE

The $GLOBIGNORE variable is a colon-separated list of patterns defining the set of filenames to be ignored by filename expansion. If a filename matched by a filename expansion pattern also matches one of the patterns in $GLOBIGNORE, it is removed from the list of matches. This should be used carefully as it may impact other assumptions in your scripts like when counting files in a directory.

The Host Environment Variables: HOSTNAME, HOSTTYPE, OSTYPE, and MACHTYPE

The $HOSTNAME contains the name of the current host and $HOSTTYPE refers to the machine type on which Bash is running. The $MACHTYPE is very similar to $HOSTTYPE but with a full description using standard GNU cpu-company-system format. The $OSTYPE variable exposes a string describing the operating system.

[me@linux ~]$ echo hostname=$HOSTNAME type=$HOSTTYPE os=$OSTTYPE mach=$MACHTYPE
hostname=linux type=x86_64 os=linux-gnu mach=x86_64-pc-linux-gnu

The Internal Field Separator Variable: IFS

IFS stands for Internal Field Separator (or Input Field Separator). The $IFS variable is often used with bash loops or with the read or printf builtin commands. It is set to a list of delimiting characters used for field separation in the shell. The default value is set to the space, tab, and newline characters, Example: IFS=$' \t\n'. When the $IFS variable is unset, it acts as if it was set back to its default value.

# Using default IFS=$' \t\n'
[me@linux ~]$ read -r a b c <<< '   A      B  C'
[me@linux ~]$ echo "$a $b $c"

# Using a custom IFS value
[me@linux ~]$ IFS=: read -r user pwhash uid gid gecos home shell \
  <<< 'root:*:0:0:System Administrator:/var/root:/bin/sh'
[me@linux ~]$ echo "$user $pwhash $uid $gid $gecos $home $shell"
root * 0 0 System Administrator /var/root /bin/sh

⚠️ During word splitting the shell will trim spaces around fields when the $IFS variable contains a mix of whitespaces and non-whitespaces.

[me@linux ~]$ IFS=' ,'
[me@linux ~]$ sentence="This is a, simple, example"
[me@linux ~]$ printf 'word -> "%s" \n' $sentence
word -> "This" 
word -> "is" 
word -> "a" 
word -> "simple" 
word -> "example" 

The Mail Variables: MAIL, MAILPATH, and MAILCHECK

The $MAIL, $MAILPATH, and $MAILCHECK are environment variables related to the local inbox system and to notify users of new emails.

The $MAIL environment variable can be optionally set to a filename or directory name used by Bash to informs the user of new mail in the specified file or Maildir-format directory. Bash uses the $MAIL variable only when the $MAILPATH variable is not set.

The $MAILPATH environment variable is a colon-separated list of filenames used by the Bash shell to periodically checks for new mail. Additionally, by using the question mark ? as a field separator, the variable allows to customize the notification message displayed to the user and the $_ variable can be used inside the custom message to be expanded to the name of the current mail file. Example: MAILPATH=<filename>?<message>;<filename>?<message>.

⚠️ When using the exclamation point ! in your message from an interactive shell, make sure to keep a space after the ! otherwise Bash will try to perform history substitution and will lead to the bash error event not found. This is generally not a problem in a shell script where history substitution is disabled by default.

[me@linux ~]$ MAILPATH="/var/mail/root?Root Got a mail in $_! ;/var/mail/jdoe?You've got a mail! "

The $MAILCHECK variable set how often, in seconds, the shell should check for mail in the files specified in the $MAILPATH or $MAIL variables. The default is 60 seconds. The shell disables mail checking when this variable is unset or is not set to a number greater than zero.

The getops Variables: OPTARG, OPTIND, and OPTERR

The $OPTARG and $OPTIND are special variables local to the caller of the getopts builtin. The $OPTARG is used to retrieve the value of the last option argument processed by getopts and $OPTIND is used to retrieve the index of the last option argument processed.

When the $OPTERR variable is set to the value 1 (default), Bash displays error messages generated by the getopts builtin command.

The Executable Command Variables: PATH and EXECIGNORE

$PATH is probably the most known and commonly used of the environment variables. It’s a colon-separated list of directories in which the shell looks for commands. This often includes the current directory and some variations of /bin and /usr/bin. The dot . or a zero-length (null) directory name indicates the current directory. A null directory name may appear as two adjacent colons ::, or as an initial or trailing colon.

[me@linux ~]$ echo $PATH

The $EXECIGNORE variable is a colon-separated list of shell patterns defining the list of filenames to be ignored by command search using $PATH. Files whose full pathnames match one of these patterns are not considered executable files for the purposes of completion and command execution via $PATH lookup.

The Shell Options Variables: BASHOPTS and SHELLOPTS

The $BASHOPTS variable is a read-only colon-separated list of shell options enabled with the shopt builtin command. The list of options in this variable will be the same as the one reported as on by the shopt command.

The $SHELLOPTS variable is a read-only colon-separated list of shell options enabled with the set builtin command and -o option. The list of options in this variable will be the same as the one reported as on by the set -o command.

👉 When the $BASHOPTS or $SHELLOPTS variables are in the environment when Bash starts up, each option in the given list will be enabled before reading any startup files.

[me@mac ~]$ set | grep OPTS

The Current Shell Path Variables: BASH and SHELL

The $BASH and $SHELL variables store the full pathname used to execute the current instance of Bash.

[me@mac ~]$ echo $BASH $SHELL
/usr/local/bin/bash /usr/local/bin/bash

The Shell Process IDs variables: BASHPID and PPID

The $PPID readonly variable contains the process ID of the current shell’s parent process while the $BASHPID provide the current Bash process ID. $BASHPID may differs from the $$ since subshells do not require Bash to be re-initialized. $BASHPID will lose its special properties when being unset.

[me@mac ~]$ echo PPID=$PPID BASHPID=$BASHPID \$\$=$$
PPID=23693 BASHPID=23764 $$=23764
[me@mac ~]$ (echo PPID=$PPID BASHPID=$BASHPID \$\$=$$)
PPID=23693 BASHPID=39074 $$=23764

The Bash Hash Commands Variable: BASH_CMDS

The $BASH_CMDS is an associative array variable that contains the list of hash commands as created by the hash builtin. $BASH_CMDS will lose its special properties when being unset.

⚠️ Elements can be directly added to this array to update the hash table. This is not good practice and the use of the hash builtin should be prefered. Removing an hash command from the associative array does not cause the hash to be removed from the hash table. The hash -d <command> syntax must be used.

[me@linux ~]$ echo ${BASH_CMDS[@]}
/bin/mv /bin/chmod /usr/local/bin/bash /usr/bin/vi /bin/ls /bin/cat
[me@linux ~]$ hash
hits    command
   1    /bin/mv
   1    /bin/chmod
  17    /usr/local/bin/bash
  17    /usr/bin/vi
   7    /bin/ls
   4    /bin/cat
[me@linux ~]$ hash -d mv
[me@linux ~]$ echo ${BASH_CMDS[@]}
/bin/chmod /usr/local/bin/bash /usr/bin/vi /bin/ls /bin/cat

The Shell Compatibility Variables: POSIXLY_CORRECT and BASH_COMPAT

The $POSIXLY_CORRECT environment variable can be set to force bash to run in POSIX mode as if bash --posix or set -o posix were used. When using set -o posix the $POSIXLY_CORRECT variable is automatically set to y.

The $BASH_COMPAT is used to enforce compatibility between Bash versions. You can set the value to a decimal number or an integer value representing the Bash version to be compatible with. Acceptable values are the compat<vers> options listed by the shopt builtin and the current Bash version. When the $BASH_COMPAT variable is unset or set to an empty string, the default value becomes the current Bash version.

[me@linux ~]$ shopt | grep compat
compat31        off
compat32        off
compat40        off
compat41        off
compat42        off
compat43        off
compat44        off
[me@linux ~]$ BASH_COMPAT=22
bash: BASH_COMPAT: 22: compatibility value out of range
[me@linux ~]$ BASH_COMPAT=42
[me@linux ~]$ echo $BASH_COMPAT

The Shell Init File Variables: ENV and BASH_ENV

The $BASH_ENV environment variable is used by Bash to define an init file to read before executing a script. This is often used for debugging purposes to define shell options or debugging traps, you can see an example in my post on How To Debug Scripts in Bash.

The $ENV variable is similar to the $BASH_ENV. It is used when the shell runs in POSIX compatibility mode.

### Define Debug environment
### Filename: my-debug-env
trap 'echo "$BASH_COMMAND" failed with error code $?' ERR

#!/usr/bin/env bash
### Example Script
### Filename: example-debug

echo "Example Script..."
bad_command &> /dev/null

### Example output with no debug env
[me@linux ~]$ ./example-debug 
Example Script...

### Example output with the debug env
[me@linux ~]$ BASH_ENV=./my-debug-env ./example-debug
Example Script...
bad_command &> /dev/null failed with error code 127

The Current Bash Execution String: BASH_EXECUTION_STRING

The $BASH_EXECUTION_STRING contains the value of the command argument to the -c Bash option. This is often used in a $BASH_ENV sourced file, or in a shell init file like .bashrc.

[me@linux ~]$ bash -c 'echo $BASH_EXECUTION_STRING'

The Bash Builtins Variable: BASH_LOADABLES_PATH

The $BASH_LOADABLES_PATH is a colon-separated list of directories in which the shell looks for dynamically loadable shell builtins specified by the enable command. The simple example below uses the sleep loadable builtin Bash example to support a fraction of a second with the sleep command. You can use the bash type command to list all the possible interpretations of a command.

[me@mac ~]$ sleep --help
usage: sleep seconds
[me@mac ~]$ BASH_LOADABLES_PATH=/usr/local/lib/bash/
[me@mac ~]$ enable -f sleep sleep
[me@mac ~]$ sleep --help
sleep: usage: sleep seconds[.fraction]
[me@mac ~]$ type -a sleep
sleep is a shell builtin
sleep is /bin/sleep

The Execution Levels Variables: SHLVL and BASH_SUBSHELL

The $SHLVL variable increment by one each time a new instance of the shell is started. This allows you to know how many nested shells are currently running. Similarly, the $BASH_SUBSHELL variable increment by one within each subshell or subshell environment when the shell begins executing in that environment. When no subshell is running, the value is 0.

[me@linux ~]$ bash
[me@linux ~]$ exit

The Bash Version Variables: BASH_VERSION and BASH_VERSINFO

The $BASH_VERSION variable contains the full version number of the Bash instance currently running. The $BASH_VERSINFO is a read-only array variable that contains version information for the current instance of Bash.

$BASH_VERSINFO[0]The major version number (the release)
$BASH_VERSINFO[1]The minor version number (the version)
$BASH_VERSINFO[2]The patch level
$BASH_VERSINFO[3]The build version
$BASH_VERSINFO[4]The release status (e.g., beta1)

The Terminal Width and Length Variables: COLUMNS and LINES

The $COLUMNS and $LINES variables are used to determine the terminal width and column length. It is used by the bash select command when creating simple interactive menus. Those variables are automatically set if the checkwinsize option is enabled using the shopt Bash builtin, or in an interactive shell upon receipt of the SIGWINCH signal.

The Bash Completion Variables

Filename Completion Variable: FIGNORE

The $FIGNORE variable is a colon-separated list of suffixes to ignore when performing filename completion. A filename whose suffix matches one of the entries in FIGNORE is excluded from the list of matched filenames.

[me@mac ~]$ ls f<TAB>
f1.txt f2.rtf f3.c f4.o
[me@mac ~]$ FIGNORE=.c:.o
[me@mac ~]$ ls f<TAB>
f1.txt f2.rtf

Hostname Completion Variable: HOSTFILE

The $HOSTFILE variable is used by the Bash shell for hostname completion. The variable contains the name of a file similar to the /etc/hosts file and which is read by the shell when a hostname completion needs to be done, for example with the ping command. If $HOSTFILE is set to an empty value or point to a non-readable file, Bash will fallback to the /etc/hosts file to obtain the list of possible hostname completions.

The Programmable Completion Variables: COMP*

The shell provides a system to support the completion of commands arguments by using the complete builtin. It allows us to control how the command arguments should be completed when the user triggers the completion.

When developing shell functions invoked by the programmable completion facilities you have access to a range of completion variables including COMP_CWORD, COMP_LINE, COMP_POINT, COMP_TYPE, COMP_KEY, COMP_WORDBREAKS, COMP_WORDS, and COMPREPLY.

The Coprocess Variable: COPROC

The $COPROC variable is an array holding the file descriptors for output from and input to an unnamed coprocess using the coproc builtin command.

The Emacs Variables: EMACS and INSIDE_EMACS

The Emacs editor provides the capability to run Bash in an Emacs shell buffer. Emacs will set the environment variable $EMACS when the shell starts with value ‘t’. When this variable is found, Bash will disable line editing. Similarly, Emacs will also set the environment variable $INSIDE_EMACS which will contain the Emacs version and terminal information. For example, 22.1.1,comint. In such a case, Bash may also disable line editing depending on the value of TERM.

Internationalization Variables

The variables in the table below allows you to configure your system according to a given locale category, representing an international language and its encoding. On Linux and Mac, you can use the locale -a command to list all the available locales on your systems.

[me@linux ~]$ locale -a
[me@linux ~]$ printenv | grep LANG
[me@linux ~]$ LC_TIME=fr_FR.UTF-8 date
Ven  7 aoû 2020 21:38:20 PDT
[me@linux ~]$ LC_TIME=en_US.UTF-8 date
Fri Aug  7 21:38:38 PDT 2020
[me@linux ~]$ LC_NUMERIC=fr_FR.UTF-8 printf '%g\n' 1e-2
[me@linux ~]$ LC_NUMERIC=en_US.UTF-8 printf '%g\n' 1e-2
LANGCatch-all variable. Determines the locale category for any category not specifically selected with a variable starting with LC_
LC_ALLOverrides the value of LANG and any otherLC_ variable specifying a locale category
LC_COLLATEDetermines the collation order when sorting the results of filename expansion, and it determines the behavior of range expressions, equivalence classes, and collating sequences within filename expansion and pattern matching
LC_CTYPEDetermines the interpretation of characters and the behavior of character classes within filename expansion and pattern matching](/bash/wildcards-globbing/)
LC_MESSAGESDetermines the locale used to translate double-quoted strings preceded by a $ (see Locale Translation)
LC_MONETARYDetermines the locale category used for formatting monetary numeric information
LC_NUMERICDetermines the locale category used for number formatting
LC_TIMEDetermines the locale category used for data and time formatting

The cd Builtin Variables: CDPATH, PWD, and OLDPWD

The cd builtin command will set the $PWD variable to the current working directory and the $OLDPWD variable to the previous working directory.

👉 PWD stands for the Pathname of the Working Directory.

[me@linux ~]$ echo pwd=$PWD oldpwd=$OLDPWD
pwd=/home/jdoe oldpwd=
[me@linux ~]$ cd Desktop
[me@linux ~/Desktop]$ echo pwd=$PWD oldpwd=$OLDPWD
pwd=/home/jdoe/Desktop oldpwd=/home/jdoe

The $CDPATH provides a colon-separated list of directories used as a search path for the cd builtin command. This is helpful when you have a set of directories that you access more frequently than the others. Since the directory order in the list defines the search order, I suggest that you always keep the dot . directory in the first position.

[me@linux ~]$ export CDPATH=.:~/:~/git:
[me@linux ~]$ cd my-git-repo
[me@linux /usr]$ cd Desktop

The read Builtin Variables: REPLY and TMOUT

The $REPLY variable is the default variable used by the read builtin when no name has been provided.

The $TMOUT can be optionally set to a value greater than zero that corresponds to the read builtin timeout in seconds. It is also used by the bash select loop command when prompting for user input. When this variable is set in an interactive shell, the shell will exit if no user input is received after the primary prompt is displayed and $TMOUT seconds are passed.

The User ID and Group Variables: UID, EUID, and GROUPS

The $UID read-only variable corresponds to the numeric real user id of the current user while the $EUID read-only variable is the numeric effective user id of the current user. The difference will generally occur when running a setuid command.

The $GROUPS array variable contains the list of groups the current user belongs to. The variable loses its special properties when unset.

Getting The Exit Code from Piped Commands: PIPESTATUS

The $PIPESTATUS is an array variable that contains a list of exit status values from the processes in the most-recently-executed foreground pipeline. The value will be equal to the $? value when the pipeline contains only one command. When a pipeline contains multiple processes, the $? special parameters returns only the value of the last command in the pipeline. If you need to get the exit codes of other commands, you must use the $PIPESTATUS variable. Since the variable is updated every time a command is run, you may have to store the result into a separate temporary array.

[me@linux ~]$ false | true | false
[me@linux ~]$ echo $?
[me@linux ~]$ false | true | false
[me@linux ~]$ echo ${PIPESTATUS[@]}
1 0 1
[me@linux ~]$ echo ${PIPESTATUS[@]}
[me@linux ~]$ false | true | false
[me@linux ~]$ EXIT_CODES=( "${PIPESTATUS[@]}" )
[me@linux ~]$ echo "exit_codes=(${EXIT_CODES[@]}) pipe_status=(${PIPESTATUS[@]})"
exit_codes=(1 0 1) pipe_status=(0)

The Temporary Directory: TMPDIR

When the $TMPDIR environment variable is set, Bash and many other Linux utilities use its value as the name of a directory where temporary files can be created. The mktemp command uses $TMPDIR by default or fallback to /tmp when $TMPDIR is not set.

The Directory Stack Variable: DIRSTACK

The $DIRSTACK array variable contains the current contents of the directory stack in the same order as displayed by the dirs builtin command. Directories are added or removed from the stack by using the pushd and popd builtins. Assignment to the $DIRSTACK variable will not change the current directory. The variable $DIRSTACK loses its special properties when unset.

[me@linux ~]$ echo ${DIRSTACK[@]}
[me@linux ~]$ pushd Desktop
~/Desktop ~
[me@linux ~]$ echo ${DIRSTACK[@]}
/home/jdoe/Desktop /home/jdoe
[me@linux ~]$ popd
[me@linux ~]$ echo ${DIRSTACK[@]}

The Interactive Shell End Of Input Variable: IGNOREEOF

An interactive Bash shell will exit when it receives an EOF character as a sole input. This can be produced by using the Ctrl+D keys. Bash provides the $IGNOREEOF variable to change this default behavior and allow the user to define how many EOF characters is required before the shell exit. When $IGNOREEOF is set to an empty string or a non-numeric value, then the shell fallback to a default value of 10 EOF characters. If the variable is unset, the first EOF received will terminate the current shell session. Alternatively, the set -o ignoreeof may be set which will use the 10 EOF character default value.

[me@linux ~]$ <ctrl>+<D>
Saving session...completed.

[Process completed]

[me@linux ~]$ IGNOREEOF=1
[me@linux ~]$ <ctrl>+<D>
Use "logout" to leave the shell.
[me@linux ~]$ <ctrl>+<D>
Saving session...completed.

[Process completed]

A Random Generated Variable: RANDOM

The $RANDOM variable produces a pseudo-random integer each time it is referenced. The integer range between 0 and 32767. Assigning a value to $RANDOM will seed the variable and ensure reproductability which may be desired in some cases.

[me@linux ~]$ for ((i=1;i<=3;i++)); do echo $i=$RANDOM; done
[me@linux ~]$ for ((i=1;i<=3;i++)); do echo $i=$RANDOM; done
[me@linux ~]$ RANDOM=1; for ((i=1;i<=3;i++)); do echo $i=$RANDOM; done
[me@linux ~]$ RANDOM=1; for ((i=1;i<=3;i++)); do echo $i=$RANDOM; done

The Shell Run Time Variable: SECONDS

The $SECOND variable provides the number of seconds since the shell started in interactive mode or since a shell script started executing. Assignment to $SECOND will reset the variable to the value provided and start incrementing again from this given value.

[me@linux ~]$ echo $SECONDS
[me@linux ~]$ echo $SECONDS
[me@linux ~]$ SECONDS=0
[me@linux ~]$ echo $SECONDS
[me@linux ~]$ echo $SECONDS

The Time Builtin Variable: TIMEFORMAT

The $TIMEFORMAT variable is used to define how to format the output string from the time builtin. The format strings use the % character as an escape sequence. The square bracket in the table below represent optional portions. When not set, Bash default to the format $'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'. If the value is null, then no timing information will be displayed.

%%A literal %
%[p][l]RThe elapsed time in seconds
%[p][l]UThe number of CPU seconds spent in user mode
%[p][l]SThe number of CPU seconds spent in system mode
%PThe CPU percentage, computed as (%U + %S) / %R
[me@linux ~]$ time sleep 5

real    0m5,023s
user    0m0,001s
sys     0m0,004s
[me@linux ~]$ TIMEFORMAT='%0R'
[me@linux ~]$ time sleep 5