Skip to content
Home
Linux Environment Variables: Complete Guide

Linux Environment Variables: Complete Guide

Linux Linux 7 min read 1457 words Beginner ExcellentWiki Editorial Team

Environment variables are key-value pairs that configure the behavior of programs and the shell environment. They control everything from the system PATH to application secrets, locale settings, and editor preferences.

What Are Environment Variables?

Environment variables are part of the environment inherited by every process. A child process receives a copy of its parent’s environment. Changes in the child do not affect the parent. This inheritance model is fundamental to Unix process management.

Viewing Environment Variables

# Show all environment variables
env
printenv

# Show a specific variable
echo "$PATH"
printenv PATH
echo "${HOME}"

# Show all shell variables (including non-exported)
set

Setting and Unsetting

Shell Session (Temporary)

# Set for current shell session
MY_VAR="hello"
export MY_VAR       # make available to child processes

# Set and export in one step
export MY_VAR="hello"

# Set for a single command only
MY_VAR="hello" ./myprogram

# Unset a variable
unset MY_VAR

# Remove a variable from environment (still exists in shell)
export -n MY_VAR

Persistence Per-User

# ~/.bashrc (interactive non-login shells)
export EDITOR=nano
export VISUAL=nano
export PATH="$HOME/.local/bin:$PATH"

# ~/.profile or ~/.bash_profile (login shells)
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
export PATH="$JAVA_HOME/bin:$PATH"

# ~/.pam_environment (system-wide variable file)
# Format: VARIABLE DEFAULT=value

Persistence System-Wide

# /etc/environment — simple KEY=value pairs (no shell syntax)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
JAVA_HOME=/usr/lib/jvm/java-11-openjdk

# /etc/profile.d/*.sh — scripts sourced during login
# /etc/profile.d/java.sh
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
export PATH="$JAVA_HOME/bin:$PATH"

# /etc/bash.bashrc — applies to all Bash users

Standard Environment Variables

System Configuration

PATH        # Colon-separated list of directories to search for executables
HOME        # Current user's home directory
USER        # Current username
LOGNAME     # Username (usually same as USER)
SHELL       # Path to the default shell
LANG        # Locale setting (e.g., en_US.UTF-8)
TZ          # Timezone (e.g., America/New_York)
TERM        # Terminal type (e.g., xterm-256color)
PWD         # Current working directory
OLDPWD      # Previous working directory

Application Configuration

EDITOR      # Default editor (nano, vim, etc.)
VISUAL      # Visual editor (often same as EDITOR)
PAGER       # Page through output (less, more)
BROWSER     # Default web browser
LANG        # Language and encoding
LC_ALL      # Override all locale settings
LC_COLLATE  # Sort order
LC_TIME     # Date/time format

Development Variables

JAVA_HOME       # Java installation directory
GOPATH          # Go workspace path
NODE_PATH       # Node.js module search path
PYTHONPATH      # Python module search path
RUSTUP_HOME     # Rust toolchain location
GEM_PATH        # Ruby gem search path

PATH Management

The PATH variable is the most frequently modified environment variable. It controls where the shell looks for executables.

# View current PATH (colon-separated)
echo "$PATH"

# Prepend a directory (checked first)
export PATH="$HOME/bin:$PATH"

# Append a directory (checked last)
export PATH="$PATH:/opt/custom/bin"

# Remove duplicate entries
export PATH=$(echo "$PATH" | tr ':' '\n' | awk '!seen[$0]++' | tr '\n' ':' | sed 's/:$//')

# Check which executable will be used
which python
type python
command -v python

Loading Order

Understanding the order in which shell configuration files are loaded helps you set variables correctly:

Login Shell (e.g., SSH, tty login)

  1. /etc/profile
  2. /etc/profile.d/*.sh
  3. ~/.bash_profile (preferred), or ~/.bash_login, or ~/.profile
  4. ~/.bashrc (usually sourced from ~/.bash_profile)

Interactive Non-Login Shell (e.g., new terminal tab)

  1. /etc/bash.bashrc
  2. ~/.bashrc

Non-Interactive Shell (e.g., script execution)

  1. No profile or rc files
  2. Inherits parent’s environment

Security Best Practices

# Never hardcode secrets in configuration files
# Instead, read from files or use secret management

# Load API key from file (safer)
export API_KEY=$(cat /run/secrets/api_key)

# Use read-only and local scope
readonly API_KEY="temporary"
export API_KEY

# Sanitize the environment for untrusted commands
env -i /usr/bin/safe-command

# Remove dangerous variables before executing untrusted code
unset LD_PRELOAD
unset LD_LIBRARY_PATH

Troubleshooting

# Check if variable is set
echo "${MY_VAR:-unset}"    # shows 'unset' if not set
echo "${MY_VAR:?not set}"  # error and exit if not set

# Debug variable inheritance
env | grep MY_VAR

# Test in a subshell
(bash -c 'echo "In subshell: $MY_VAR"')

# Find where a variable is set
grep -r "MY_VAR=" ~/.bashrc ~/.profile /etc/profile /etc/environment 2>/dev/null

# Export variable to running process
# First find PID, then use gdb (not recommended for production)

Real-World Implementation Tips

Production Considerations

When moving from development to production, several factors become critical. Error handling should be comprehensive — every external call (database, API, file system) should have proper error checking, logging, and retry logic where appropriate. Performance monitoring through metrics and structured logging helps identify bottlenecks before they affect users.

Testing Strategy

A thorough testing approach combines multiple levels:

  • Unit tests verify individual functions and methods in isolation
  • Integration tests validate that components work together correctly
  • Edge case tests cover boundary conditions, empty inputs, and error states
  • Performance tests ensure the system meets latency and throughput requirements

Test data should be realistic but controlled. Mock external dependencies to make tests fast and deterministic. Aim for tests that are independent, repeatable, and fast enough to run on every commit.

Documentation

Good documentation is essential for maintainable code. Follow these principles:

  • Document the “why” not just the “what” — explain design decisions
  • Keep examples up to date with the code
  • Include usage examples for public APIs
  • Document configuration options and their defaults
  • Explain error conditions and recovery strategies

Security Best Practices

Security should be considered throughout development:

  • Validate all inputs at system boundaries
  • Use parameterized queries for database access
  • Store secrets in environment variables or secret managers
  • Keep dependencies updated to patch vulnerabilities
  • Apply the principle of least privilege

Performance Optimization

Optimize based on measured data, not assumptions:

  1. Profile before optimizing — identify actual bottlenecks
  2. Measure the impact of each change
  3. Consider the trade-off between speed and readability
  4. Cache expensive operations with appropriate invalidation
  5. Use connection pooling for database and network resources

Monitoring and Observability

Production systems need visibility:

  • Structured logging with correlation IDs for request tracking
  • Metrics for latency, throughput, error rates, and resource usage
  • Health check endpoints for load balancers and orchestration
  • Distributed tracing for request flows across services
  • Alerts for anomaly detection based on baselines

These patterns apply across all programming languages and frameworks. The specific implementation varies, but the principles remain consistent.

FAQ

Q: What is the difference between local variable and environment variable? A: A local (shell) variable is only available in the current shell. An environment variable is passed to child processes via export.

Q: How do I set environment variables permanently? A: Add export VAR=value to ~/.bashrc (user-specific, interactive) or ~/.profile (login shells). For system-wide, use /etc/environment or /etc/profile.d/*.sh.

Q: Why is my PATH different when I use sudo? A: Sudo resets the environment for security. Use sudo -E to preserve the environment or configure env_keep in /etc/sudoers.

Q: How do I reload environment variables without logging out? A: Source the file: source ~/.bashrc or . ~/.bashrc.

Q: What happens when I set a variable without export? A: It is a shell variable — available in the current shell but not inherited by child processes. Use export to make it an environment variable.

Q: How do I see all environment variables for a process? A: cat /proc/<PID>/environ | tr '\0' '\n' shows the environment of a running process.

Environment Variable Management

Setting Variables System-Wide

# /etc/environment — simple KEY=VALUE pairs, no shell expansion
JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
# /etc/profile — Bourne-compatible shells, supports expansion
export EDITOR=nano
# /etc/bash.bashrc — all bash users
alias ll='ls -alF'

User-Specific Files

Shell initialization files load in this order for bash:

  1. /etc/profile — system-wide
  2. ~/.profile — login shell
  3. ~/.bashrc — interactive non-login shell
  4. ~/.bash_profile — overrides ~/.profile if exists

For security, avoid storing secrets in environment variables that child processes inherit. Use dedicated secret managers or encrypted files where possible.

Working with Environment in Scripts

# Set default value if unset
DB_HOST="${DB_HOST:-localhost}"
# Require a variable to be set
DB_PASS="${DB_PASSWORD:?must be set}"
# Export all variables from a file
set -a; source .env; set +a
# Print all environment variables
env | sort

PATH Management

# Prepend safely (no duplicate entries)
pathprepend() {
    export PATH="$1:$PATH"
    PATH=$(echo "$PATH" | tr ':' '\n' | awk '!seen[$0]++' | tr '\n' ':' | sed 's/:$//')
---

Environment Variable Security

Never hardcode secrets in scripts or configuration files. Use environment variables loaded from secure sources:

# Load from encrypted file
source <(gpg -d secrets.env.gpg)

# Use a secret manager
secret=$(vault kv get -field=password secret/db)
export DB_PASSWORD="$secret"

# Temporary environment for a single command
DB_PASSWORD=$(cat /run/secrets/db_pass) myapp

Docker and Container Environments

# Docker environment variables
docker run -e DB_HOST=localhost -e DB_PORT=5432 myapp

# Docker Compose environment file
# .env file
docker-compose --env-file .env.prod up

# Kubernetes ConfigMap and Secrets
# kubectl create configmap app-config --from-literal=log_level=debug
# kubectl create secret generic db-cred --from-literal=password=...

Debugging Environment Issues

# Compare environment between shells
diff <(env) <(ssh user@host env)

# Trace variable resolution
set -x; echo $PATH; set +x

# Check if a variable is set
[[ -z "$MY_VAR" ]] && echo "MY_VAR is unset or empty"

For a comprehensive overview, read our article on Bash Scripting Basics.

For a comprehensive overview, read our article on Cron Jobs Guide.

Section: Linux 1457 words 7 min read Beginner 756 articles in section Report inaccuracy Back to top