Linux: Environment Variables and PATH
Environment variables are key-value pairs the operating system uses to store configuration. They determine where the Shell looks for commands (PATH), what language to use (LANG), and which editor to use (EDITOR).
📋 Prerequisites: You should first complete
- Lesson 9: User and Group Management
1. What You Will Learn
- The role of environment variables
- How PATH works
- export and unset operations
- Shell configuration file loading order
- Adding new tools to PATH
2. A "command not found" Story
(1) The Pain: Installed a Program But Can't Find It
Alex installed the Python tool httpie with pip install --user, but typing http gave:
http example.com
# Command 'http' not found
Alex was confused: "I installed it, why can't the system find it?"
(2) PATH — Telling the Shell Where to Find Programs
Bob explained: "The program is installed, but the Shell doesn't know where to look. The PATH environment variable is the Shell's 'treasure map.'"
echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# ~/.local/bin is not in PATH, so the Shell can't find http
ls ~/.local/bin/http*
# /home/charlie/.local/bin/http
# Add ~/.local/bin to PATH
export PATH="$PATH:$HOME/.local/bin"
http example.com # Now it works
(3) The Benefit: Understanding the Mechanism Behind Everything
Alex learned that putting export PATH="$PATH:~/bin" in .bashrc makes it permanent. Now whenever he installs a new tool, he knows to check if the installation directory is in PATH.
3. Knowledge Points
(1) What Are Environment Variables
Environment variables are key-value pairs stored in the operating system that all child processes inherit.
# View all environment variables
printenv
# View individual variables
echo $HOME
echo $USER
echo $SHELL
echo $LANG
echo $PWD
Common environment variables:
| Variable | Meaning | Typical value |
|---|---|---|
HOME |
Current user's home directory | /home/alice |
USER |
Current username | alice |
SHELL |
Current Shell path | /bin/bash |
PATH |
Command search path | /usr/bin:/bin:/usr/local/bin |
LANG |
Language and encoding | en_US.UTF-8 |
PWD |
Current working directory | /home/alice/projects |
OLDPWD |
Previous working directory | /etc |
EDITOR |
Default editor | vim |
(2) PATH — Command Search Path
When you type ls, the Shell searches for the ls program in each directory listed in PATH, in order. If found, it executes; if not, it reports command not found.
# View current PATH
echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Find which directory a command is in
which ls
# /usr/bin/ls
# View all possible locations for a command (including aliases and functions)
type ls
# ls is aliased to `ls --color=auto'
(3) Setting and Unsetting Environment Variables
# Temporary setting (only effective in current Shell)
MY_VAR="hello"
# Export as environment variable (child processes can access it)
export MY_VAR="hello"
# Set and export in one command
export MY_VAR="hello"
# Unset an environment variable
unset MY_VAR
# Temporarily set for a single command (without polluting current environment)
LANG=ja_JP.UTF-8 date
(4) Shell Configuration File Loading Order
Understanding the loading order is important — it explains why sometimes changes to ~/.bashrc don't take effect:
Login Shell (SSH login, tty login):
/etc/profile
~/.bash_profile (if it exists, the following two are skipped)
~/.bash_login
~/.profile
Non-login Shell (opening a new terminal):
/etc/bash.bashrc
~/.bashrc
ℹ️ Note:
.bashrcand.profileload at different times — SSH login loads.profile, while opening a new terminal loads.bashrc. The best practice is to addsource ~/.bashrcin.profileand put all configuration in.bashrc, so it works regardless of how you log in.
Best practice: Add this to .bash_profile:
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
Then put all custom configuration in .bashrc.
(5) ▶ Example: View and Set Environment Variables
# View environment variables
echo "My home directory is: $HOME"
echo "Current user: $USER"
echo "My Shell: $SHELL"
# Set a temporary variable
export GREETING="Hello from Linux"
echo $GREETING
# Open a new terminal window and check if $GREETING is still there
# Answer: No — temporary variables only exist in the current Shell
Output:
TEXTMy home directory is: /home/alice Current user: alice My Shell: /bin/bash Hello from Linux
(6) ▶ Example: Understanding PATH
# View current PATH
echo $PATH | tr ':' '\n' # Display one path per line
# Find which directory ls is loaded from
which ls
# /usr/bin/ls
# What happens if PATH is wrong?
PATH="" # Clear PATH (dangerous!)
ls
# bash: ls: No such file or directory
# Restore PATH
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Output:
TEXT/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/bin/ls
(7) ▶ Example: Add ~/scripts to PATH (Permanent)
# Create your own scripts directory
mkdir -p ~/scripts
# Add ~/scripts to PATH (write to .bashrc)
echo 'export PATH="$PATH:$HOME/scripts"' >> ~/.bashrc
> 💡 Tip: To make environment variables permanent, you must write the `export` command to `~/.bashrc` (or `~/.profile`). After modifying, run `source ~/.bashrc` to apply immediately; otherwise the new configuration will only load in newly opened terminals.
# Reload
source ~/.bashrc
# Verify
echo $PATH | tr ':' '\n' | grep scripts
# /home/alice/scripts
Output:
TEXT/home/alice/scripts
(8) ▶ Example: Common Development Environment Variable Configuration
# Add the following to ~/.bashrc
# Default editor
export EDITOR=vim
# Locale
export LANG=en_US.UTF-8
# Python development
export PYTHONSTARTUP=~/.pythonrc # Python interactive startup script
export PIP_REQUIRE_VIRTUALENV=true # pip requires virtual environment
# Node.js development
export NODE_ENV=development
export npm_config_prefix=~/.npm-global
# Go development
export GOPATH=$HOME/go
export PATH="$PATH:$GOPATH/bin"
# Your own scripts
export PATH="$PATH:$HOME/scripts"
export PATH="$PATH:$HOME/.local/bin"
Output:
TEXTEDITOR=vim LANG=en_US.UTF-8 PYTHONSTARTUP=/home/alice/.pythonrc PIP_REQUIRE_VIRTUALENV=true NODE_ENV=development GOPATH=/home/alice/go
(9) ▶ Example: Check If a Command Can Be Found
# Use which to find the command path
which python3
# /usr/bin/python3
# Use type to check command type (alias/function/builtin/external)
type ls
# ls is an alias for `ls --color=auto'
type cd
# cd is a shell builtin
type node
# node is /usr/bin/node
# Use command -v (most reliable method)
command -v python3
# /usr/bin/python3
Output:
TEXT/usr/bin/python3 ls is an alias for `ls --color=auto' cd is a shell builtin node is /usr/bin/node /usr/bin/python3
(10) ▶ Comprehensive Example: Debugging a "command not found" Problem
#!/bin/bash
# debug-path.sh - Debug command-not-found issues
CMD="${1:-http}"
echo "=== 1. What is the command ==="
type "$CMD" 2>/dev/null || echo "type: $CMD not found"
echo ""
echo "=== 2. Which PATH directories contain this command ==="
IFS=':' read -ra PATHS <<< "$PATH"
for dir in "${PATHS[@]}"; do
if [ -f "$dir/$CMD" ]; then
echo "Found: $dir/$CMD"
fi
done
echo ""
echo "=== 3. Global search with find ==="
find /usr /opt $HOME -name "$CMD" -type f 2>/dev/null | head -5
echo ""
echo "=== 4. If found but not in PATH ==="
echo "Run: export PATH=\"\$PATH:/found/directory\""
❓ FAQ
Q: Does PATH order matter? A: Very much! The Shell searches PATH directories in order and stops at the first match. If
/usr/local/bincomes first, it takes priority over/usr/bin. This is why newly installed programs sometimes still run an older version — check your PATH order.
Q: Will environment variables disappear after a reboot? A: Temporary variables set with
exportwill be lost after a reboot. To persist them, write theexportcommands to a Shell configuration file (~/.bashrcor~/.bash_profile).
Q: Which executes first,
.bashrcor.bash_profile? A: Login Shell:/etc/profile→~/.bash_profile→~/.bash_login→~/.profile(if previous files don't exist). Non-login Shell:/etc/bash.bashrc→~/.bashrc.
Q: How do I set global environment variables (for all users)? A: Write to
/etc/environment(simple key-value pairs, no scripting) or/etc/profile.d/custom.sh(supports Shell syntax, requires root privileges).
Q: What's the difference between
printenvandset? A:printenvonly shows environment variables (exported ones).setshows all variables including Shell local variables and functions. Useprintenvfor a complete environment view,setfor script debugging.
📖 Summary
- Environment variables are OS-level key-value pairs; child processes inherit parent's environment variables
export VAR=valuesets and exports;unset VARremoves- PATH defines command search paths; order determines which version takes priority
which cmd/type cmdto find command locations- Configuration goes in
~/.bashrc(non-login Shell) or~/.profile(login Shell) - After modifying config files, run
source ~/.bashrcto apply immediately
📝 Exercises
- Basic (Difficulty ⭐): View the current PATH (use
tr ':' '\n'for clearer line-by-line display), and usewhich python3andtype cdto understand command types - Intermediate (Difficulty ⭐⭐): Create a
~/scriptsdirectory, write a simplehello.shscript, add it to PATH and run it directly; setEDITOR=vim(ornano) in.bashrcand verify withsource - Advanced (Difficulty ⭐⭐⭐): Write a
debug-path.shscript that takes a command name as an argument and automatically checks whether it's in PATH, which directory contains it, and suggests a fix if it's not in PATH