Environment variable

On this page 7

An environment variable is a named string value, written as NAME=value, that belongs to the environment of a process and is passed by default to every child process it starts. In Linux and its shells, environment variables carry settings such as the search path for commands, the home directory, the preferred language and the default editor, letting programs adapt their behavior without command-line options or configuration files.

Environment variables connect the shell and terminal to everything launched from them. A value exported in Bash or Zsh is visible to the programs that shell starts, which is why variables such as PATH, HOME and LANG shape almost every command a user runs.

How the process environment works

Every Linux process has an environment block, an array of NAME=value strings stored in its memory next to the command-line arguments. When a process creates a child with fork and runs a new program with execve, the environment is copied into the new program unless the caller supplies a different one. In C, programs read it with getenv; in the shell, it is referenced as $NAME.

The inheritance is one-way and by copy. A child can modify its own environment, but the change never travels back to the parent. This is why a shell script that sets a variable cannot alter the variables of the interactive shell that ran it, unless the script is sourced with source or ., which executes it inside the current shell.

The kernel exposes a running process’s initial environment in /proc/PID/environ, as null-separated strings readable only by the process owner and root. The kernel does not interpret the contents; meaning is assigned entirely by the programs that read them.

Shell variables versus environment variables

Shells distinguish local shell variables from exported environment variables. An assignment such as NAME=value creates a shell variable visible only inside the current shell; export NAME marks it for inclusion in the environment of child processes.

SyntaxScopeTypical use
NAME=valueCurrent shell onlyTemporary values inside scripts
export NAME=valueCurrent shell and all later childrenSettings for the rest of the session
NAME=value commandOne command onlyRun a program with a modified setting
env NAME=value commandOne command onlySame effect, works from any program
env -i commandEmpty environmentTest a program in a clean environment
unset NAMERemoves the variableClear a value that interferes
Ways to set a variable in Bash

The commands env and printenv list the exported environment, while set in Bash also shows local variables and functions. Confusing the two lists is a common reason why a variable appears to be set but a launched program does not see it.

Common environment variables in Linux

A small group of variables is standardized by POSIX or by long convention and read by many programs. The table lists the ones administrators meet most often.

VariableMeaningExample value
PATHDirectories searched for commands, separated by colons/usr/local/bin:/usr/bin:/bin
HOMEUser’s home directory/home/anna
USERName of the current useranna
SHELLUser’s login shell/bin/bash
LANG and LC_ALLLocale for language, sorting and formatsen_US.UTF-8
TERMTerminal type for screen controlxterm-256color
EDITORPreferred text editorvim
TZTime zone overrideEurope/Berlin
Frequently used environment variables

Applications add their own variables, such as JAVA_HOME or proxy settings in HTTP_PROXY. Names are case-sensitive, and by convention environment variables use uppercase letters, digits and underscores, while lowercase names are left for local shell variables.

Where variables are defined persistently

A variable exported in a terminal disappears when the session ends. Persistent values are written to startup files, and choosing the right file depends on whether the shell is a login shell or an interactive non-login shell.

LocationRead byScope
/etc/environmentPAM at loginAll users; plain NAME=value lines, no shell syntax
/etc/profile and /etc/profile.d/Login shellsAll users
~/.profile or ~/.bash_profileBash login shellsOne user
~/.bashrcInteractive Bash shellsOne user; aliases and prompt
~/.zshenv and ~/.zshrcZshOne user
Environment= in a systemd unitsystemd for one serviceOne service only
Startup files for environment settings

Services started by systemd do not read shell startup files, so a variable defined in ~/.bashrc is invisible to them. Daemons need their values in the unit file, an EnvironmentFile, or the systemd manager environment. Cron jobs likewise run with a minimal environment, which explains many scripts that work in a terminal but fail on schedule.

Security considerations and common mistakes

Environment variables are convenient but not a secure storage place. Their values are inherited by every child process, may appear in crash reports and debugging output, and can be read through /proc by the same user.

  • Secrets in the environment: passwords and tokens leak easily to child processes and logs; files with restricted permissions or a secrets manager are safer.
  • Overwriting PATH: writing PATH=/opt/tool/bin instead of appending :$PATH removes standard commands from the session.
  • Current directory in PATH: an entry such as . lets a malicious file with a common command name run unexpectedly.
  • sudo resets the environment: with the default env_reset policy, most user variables are dropped for the elevated command.
  • Unquoted expansion: $NAME without quotes splits on spaces and expands wildcards; "$NAME" keeps the value intact.

Dynamic linker variables such as LD_PRELOAD and LD_LIBRARY_PATH deserve special care because they change which code a program loads. For setuid programs, the dynamic linker ignores them for exactly this reason.

The idea in brief

When a program starts on a computer, it often needs a few basic facts: who the user is, which language to show and where to find other programs. Environment variables are short labeled notes that carry this information.

Think of them as a note handed from a parent to a child. Each program receives a copy of the notes from the program that started it and passes them on to any program it starts. Changing a note affects only the copies made afterwards, never the original.

A practical scenario

A data analyst installs a newer version of Python into /opt/python3.12/bin on a shared Linux server. Typing python3 still starts the older system version, because the shell searches PATH from left to right and finds /usr/bin/python3 first.

The analyst adds export PATH="/opt/python3.12/bin:$PATH" to ~/.profile, logs in again and confirms the change with command -v python3. The new directory now comes first, while all standard commands remain available because the old value was appended rather than replaced.

A nightly report scheduled with cron, however, still uses the old interpreter. The analyst learns that cron uses its own minimal environment and sets the full interpreter path in the job. Both interactive work and scheduled jobs then run the intended Python version.