Environment Variables¶
Environment variables store configuration that programs can access. Understanding how they work is essential for proper shell configuration.
What Are Environment Variables?¶
Environment variables are:
- Key-value pairs available to all processes
- Inherited by child processes
- Used to configure program behavior
Shell vs Environment Variables¶
There's an important distinction:
Shell variables - Local to current shell:
myvar="hello" # Not exported
echo $myvar # Works in this shell
bash -c 'echo $myvar' # Empty - not inherited
Environment variables - Inherited by child processes:
Setting Variables¶
Basic Assignment¶
NAME="value" # No spaces around =
NAME=value # Quotes optional if no spaces
NAME="value with spaces"
NAME='literal $value' # Single quotes: no expansion
Export¶
Make variable available to child processes:
One-Time Environment¶
Set for single command:
Unset¶
Remove a variable:
Common Environment Variables¶
System Variables¶
| Variable | Purpose |
|---|---|
HOME | User's home directory |
USER | Current username |
SHELL | User's default shell |
PWD | Current working directory |
OLDPWD | Previous directory |
HOSTNAME | Machine hostname |
TERM | Terminal type |
LANG | Language/locale |
TZ | Timezone |
Shell Configuration¶
| Variable | Purpose |
|---|---|
PATH | Executable search path |
PS1 | Primary prompt |
PS2 | Continuation prompt |
HISTSIZE | History length |
HISTFILE | History file location |
HISTCONTROL | History behavior |
Program Configuration¶
| Variable | Purpose |
|---|---|
EDITOR | Default text editor |
VISUAL | Visual editor |
PAGER | Default pager (less, more) |
BROWSER | Default web browser |
MANPATH | Manual page search path |
The PATH Variable¶
PATH tells the shell where to find executables:
Directories are separated by colons, searched left to right.
Adding to PATH¶
# Prepend (searched first)
export PATH="$HOME/.local/bin:$PATH"
# Append (searched last)
export PATH="$PATH:/opt/myapp/bin"
Best Practice¶
Check before adding to avoid duplicates:
# Add only if not already present
add_to_path() {
[[ ":$PATH:" != *":$1:"* ]] && export PATH="$1:$PATH"
}
add_to_path "$HOME/.local/bin"
Finding Commands¶
which python # First match in PATH
type python # What python resolves to
command -v python # POSIX way to check
Viewing Variables¶
All Environment Variables¶
All Variables (including shell)¶
Specific Variable¶
Variable Scope¶
Global (Exported)¶
Available everywhere after export:
Local to Script¶
Not exported, only in current shell:
Local to Function¶
Using local keyword:
Default Values¶
Use Default if Unset¶
echo ${NAME:-default} # Use 'default' if NAME unset
echo ${NAME:=default} # Set and use 'default' if unset
echo ${NAME:+alternate} # Use 'alternate' if NAME IS set
echo ${NAME:?error msg} # Error if NAME unset
Examples:
unset NAME
echo ${NAME:-John} # John
NAME="Alice"
echo ${NAME:-John} # Alice
echo ${UNDEFINED:?Must be set} # Error: Must be set
Persistent Configuration¶
For Interactive Shells¶
Add to ~/.bashrc:
For Login Sessions¶
Add to ~/.bash_profile (sources .bashrc):
System-Wide¶
Add to /etc/environment or /etc/profile.d/*.sh:
Common Patterns¶
XDG Base Directories¶
Standard locations for application data:
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_DATA_HOME="$HOME/.local/share"
export XDG_CACHE_HOME="$HOME/.cache"
Language-Specific¶
# Python
export PYTHONPATH="$HOME/lib/python"
export VIRTUAL_ENV="$HOME/.venv"
# Node.js
export NODE_PATH="$HOME/.node_modules"
export NPM_CONFIG_PREFIX="$HOME/.npm-global"
# Go
export GOPATH="$HOME/go"
export GOBIN="$GOPATH/bin"
# Rust
export CARGO_HOME="$HOME/.cargo"
export RUSTUP_HOME="$HOME/.rustup"
Development¶
Special Variables¶
Variables set by bash:
| Variable | Meaning |
|---|---|
$? | Last command exit status |
$$ | Current shell PID |
$! | Last background job PID |
$0 | Script name |
$# | Number of arguments |
$@ | All arguments (individually quoted) |
$* | All arguments (as single word) |
$_ | Last argument of previous command |
See Special Variables for complete reference.
Security Considerations¶
Never Export Secrets¶
Don't put sensitive data in shell config:
# Bad - visible in ps, env dumps
export API_KEY="secret123"
# Better - use files with restricted permissions
chmod 600 ~/.secrets
source ~/.secrets
Sanitize User Input¶
When using variables in commands:
# Quote to prevent word splitting and globbing
rm "$file" # Not: rm $file
# Validate before use
[[ "$input" =~ ^[a-z]+$ ]] || exit 1
Debugging¶
Trace Variable Expansion¶
Check If Set¶
[[ -v VARNAME ]] && echo "Set"
[[ -z "$VARNAME" ]] && echo "Empty or unset"
[[ -n "$VARNAME" ]] && echo "Not empty"
Try It¶
-
Explore current environment:
-
Practice variable scope:
-
Use defaults:
-
Modify PATH:
Summary¶
| Action | Syntax |
|---|---|
| Set shell variable | VAR=value |
| Export to environment | export VAR=value |
| View variable | echo $VAR |
| View all environment | env or printenv |
| View all variables | set |
| Unset variable | unset VAR |
| Default if unset | ${VAR:-default} |
| Set default if unset | ${VAR:=default} |
| Prepend to PATH | export PATH="$NEW:$PATH" |