Environment variables are named values that programs inherit from the process that started them: PATH tells the shell where to find commands, HOME points to your home directory, and applications read settings like DATABASE_URL or NODE_ENV from them. Knowing where they come from — and where they don’t reach — solves a lot of “works in my shell, fails in cron” puzzles.

View variables

printenv                # all environment variables
printenv PATH           # one variable
echo "$HOME"
env | grep -i proxy

set (without arguments) shows shell variables and functions too — more than the environment.

Set a variable

GREETING="hello"          # shell variable: only this shell sees it
export GREETING           # now child processes inherit it
export APP_ENV=production # set and export in one step

A plain assignment creates a shell variable. export turns it into an environment variable, passed to programs you start from this shell.

For a single command only:

APP_ENV=staging ./run.sh

Remove it:

unset GREETING

Make it permanent for your user

Add export lines to a startup file:

  • ~/.bashrc — read by interactive non-login shells (most terminal windows, and on Debian/Ubuntu also sourced by login shells via ~/.profile).
  • ~/.profile or ~/.bash_profile — read by login shells (SSH logins).
echo 'export EDITOR=nano' >> ~/.bashrc
source ~/.bashrc

The differences between these files are covered in .bashrc vs .bash_profile.

System-wide

  • /etc/environment — simple KEY=value lines (no export, no variable expansion), read at login by PAM for all users:
HTTP_PROXY=http://10.0.0.1:3128
  • /etc/profile.d/*.sh — shell scripts sourced by login shells, so you can use logic and export:
# /etc/profile.d/java.sh
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
export PATH="$JAVA_HOME/bin:$PATH"

Changes apply at the next login.

PATH

PATH is a colon-separated list of directories searched for commands, in order:

echo "$PATH"
export PATH="$HOME/.local/bin:$PATH"     # prepend a directory

Always include $PATH when changing it, or you’ll lose access to normal commands for that session. See the PATH variable.

Where variables don’t reach

Environment variables flow from parent to child process. That’s why these common surprises happen:

systemd services

Services don’t read your .bashrc or /etc/profile. Set variables in the unit:

[Service]
Environment=NODE_ENV=production PORT=3000
EnvironmentFile=/etc/myapp/env

EnvironmentFile reads KEY=value lines — a good place for secrets (chmod 600). Apply with systemctl daemon-reload and a restart. See systemd unit files.

cron

Cron runs jobs with a minimal environment (typically PATH=/usr/bin:/bin). Define what you need at the top of the crontab, or source a file in the job:

PATH=/usr/local/bin:/usr/bin:/bin
0 3 * * * . /etc/myapp/env; /usr/local/bin/backup.sh

See cron environment variables.

sudo

sudo resets the environment for security (env_reset), keeping only a safe list. To pass something through:

sudo --preserve-env=HTTP_PROXY apt update
sudo -E command            # preserve everything (if sudoers allows it)
sudo VAR=value command     # set for that command

Docker containers

Containers get only the variables you pass: -e, --env-file or Compose’s environment:. See Docker environment variables.

.env files for applications

Many frameworks load a .env file from the project directory (Laravel, Node with dotenv, Django with django-environ). That’s application-level, not the shell environment. Load one into your shell for testing:

set -a; source .env; set +a

set -a exports every variable assigned while it’s active.

Secrets in environment variables

Convenient, but visible to the process owner and root (/proc/<pid>/environ), and sometimes leaked through crash reports or debug pages. Keep secret files chmod 600, never commit .env to Git, and turn off debug modes in production.

Useful variables

Variable Meaning
PATH Command search path
HOME Home directory
USER / LOGNAME Current user
SHELL Login shell
EDITOR / VISUAL Default editor
LANG / LC_ALL Locale
TZ Time zone override
HTTP_PROXY / HTTPS_PROXY / NO_PROXY Proxy settings
TERM Terminal type

Quick reference

Task Command
Show one printenv NAME
Set for session export NAME=value
Set for one command NAME=value cmd
Remove unset NAME
Persist (user) add to ~/.bashrc
Persist (system) /etc/environment or /etc/profile.d/
For a service Environment= / EnvironmentFile=

Related: bash scripting tutorial.

  • Linux
  • Bash
  • Configuration