Environment Variables and PATH Explained
Environment variables are how the shell and the programs it launches share configuration without every program needing its own settings file. Your home directory, your preferred editor, your terminal’s color support, and critically, which directories the shell searches to find commands, are all environment variables. Understanding them explains a lot of confusing behavior beginners run into, especially “command not found” errors for software that is clearly installed.
Viewing environment variables
printenv # list all environment variables
env # same thing, slightly different output format
echo $HOME # print a single variable
echo $PATH # print the PATH variable specifically
Some of the most commonly referenced environment variables:
| Variable | Meaning |
|---|---|
HOME | Your home directory |
USER | Your username |
PATH | Directories searched for executable commands |
SHELL | Your default shell (e.g. /bin/bash) |
EDITOR | Your preferred text editor, used by tools that need to open one |
LANG | Your system language and locale settings |
PWD | Your current working directory |
Setting a variable for the current session
myvar="hello"
echo $myvar
# hello
This creates a shell variable, visible in the current shell, but not automatically passed to programs the shell launches. To make it an environment variable, available to child processes, export it:
export myvar="hello"
Or export a variable that was already set:
myvar="hello"
export myvar
This distinction, shell variable versus environment variable, is a common source of confusion: if a program you run cannot see a variable you just set, the most likely reason is that you forgot to export it.
myvar="test"
bash -c 'echo $myvar' # prints nothing, myvar was not exported
export myvar="test"
bash -c 'echo $myvar' # prints "test", myvar is now in the environment
What PATH does
PATH is a colon-separated list of directories the shell searches, in order, whenever you type a command name without specifying its full path:
echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
When you type ls, the shell checks each directory in PATH, left to right, for an executable file named ls, and runs the first one it finds. This is why installing software in a directory that is not on PATH results in “command not found” even though the program is genuinely installed and working, the shell simply never looks there.
which ls
# /usr/bin/ls
type ls
# ls is /bin/ls
which and type both show you exactly which file on PATH would run for a given command name, useful for confirming which version of a program will actually execute when multiple copies exist in different directories.
Adding a directory to PATH
To add a new directory without losing the existing search path, append to the current value rather than replacing it:
export PATH="$PATH:/opt/mytool/bin"
"$PATH:/opt/mytool/bin" expands to the current value of PATH, followed by a colon, followed by the new directory. Overwriting PATH entirely (export PATH="/opt/mytool/bin", without $PATH: in front) is a common and disruptive mistake: it replaces the entire search path, and the shell can no longer find standard commands like ls or cd until you fix it or open a new terminal.
To have a new directory searched before the system directories (so a personal version of a command takes priority over the system one), prepend instead:
export PATH="$HOME/bin:$PATH"
Making it permanent
A variable exported at the terminal only lasts for that terminal session; close it, and the setting is gone. To persist a variable across every new terminal session, add the export line to a shell startup file that runs automatically.
For Bash, the relevant files are:
~/.bashrc # runs for interactive non-login shells (most new terminal windows)
~/.bash_profile # runs for login shells (e.g. SSH sessions, virtual consoles)
~/.profile # a more portable fallback, read by several shells including Bash
# Add a line to .bashrc
echo 'export EDITOR=vim' >> ~/.bashrc
# Apply the change to your current session without opening a new terminal
source ~/.bashrc
The distinction between login and non-login shells trips up a lot of people, since which file gets read depends on how the shell was started, and this can differ between a graphical terminal app and an SSH session on the same machine. A common, reliable workaround is to put all your real configuration in ~/.bashrc, and have ~/.bash_profile simply load it:
# Contents of ~/.bash_profile
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
This guarantees your settings apply consistently no matter which type of shell you end up in.
Aliases
Aliases are not environment variables, but they live in the same startup files and solve a related problem: giving yourself shortcuts for commands you run often.
alias ll='ls -alF'
alias gs='git status'
alias update='sudo apt update && sudo apt upgrade'
Add these to ~/.bashrc to make them available in every new terminal, the same way you would persist an environment variable.
Unsetting a variable
unset myvar
This removes the variable entirely for the current session, distinct from setting it to an empty string (myvar=""), which keeps the variable defined but empty. Some programs check whether a variable is set at all versus whether it has a value, so the distinction occasionally matters.
Frequently Asked Questions
What is an environment variable?
An environment variable is a named value stored in a process’s environment, inherited by any child process it launches. Environment variables are how the shell and other programs share configuration, like your home directory (HOME), your preferred text editor (EDITOR), and which directories to search for commands (PATH), without needing a configuration file for every single program. They are set with export in Bash and read with a dollar sign prefix, like $HOME.
What is the difference between a shell variable and an environment variable?
A shell variable, set with a plain assignment like myvar=hello, exists only within the current shell session and is not passed to any programs the shell launches. An environment variable is a shell variable that has been exported with export myvar=hello (or export myvar after a plain assignment), which makes it part of the environment inherited by every child process the shell starts. If a program you run cannot see a variable you set, it is usually because you set it as a plain shell variable and forgot to export it.
How do I permanently set an environment variable?
Add the export line to your shell’s startup file so it runs automatically every time you open a terminal, rather than typing it manually each session. For Bash, this is usually ~/.bashrc for interactive non-login shells or ~/.bash_profile / ~/.profile for login shells, depending on your distribution and how your terminal launches shells. Add a line like export EDITOR=vim to the appropriate file, save it, then either open a new terminal or run source ~/.bashrc to apply the change to your current session without restarting it.
How do I add a directory to my PATH?
Append it to the existing PATH variable rather than replacing it, since overwriting PATH entirely will make your system unable to find standard commands: export PATH=“$PATH:/new/directory” adds /new/directory to the end of the search list. Put this line in your shell startup file (such as ~/.bashrc) to make it permanent. The order of directories in PATH matters: directories listed earlier are searched first, so if the same command name exists in two directories on your PATH, the one found first (in the earliest-listed directory) is the one that runs.
Why does my system say command not found even though the program is installed?
This almost always means the program’s installation directory is not listed in your PATH. Check where the program is actually installed with a tool like find / -name programname 2>/dev/null (slow but thorough) or by checking the install method’s documentation, then add that directory to PATH as described above. This is especially common with software installed outside your distribution’s package manager, such as manually downloaded binaries, language-specific package managers (like npm global installs or pip user installs), or software compiled from source into a custom location.
What is the difference between .bashrc and .bash_profile?
Bash reads different startup files depending on whether a shell is a login shell (created when you first log in, such as via SSH or a text console) or an interactive non-login shell (such as opening a new terminal window in a desktop environment, which is already inside a login session). ~/.bash_profile (or ~/.profile) runs for login shells, while ~/.bashrc runs for interactive non-login shells. Because this split confuses more people than it helps, a very common and reliable pattern is to put all your actual configuration in ~/.bashrc and have ~/.bash_profile simply source it, guaranteeing your settings apply consistently regardless of which type of shell you end up in.