Understanding Environment Variables in Linux

Learn what Linux environment variables are, how they work, and why they matter for shells, scripts, and services. Practical examples and simple tips to view, set, export, and persist variables for DevOps beginners.

Understanding Environment Variables in Linux

Short introduction

Environment variables are key-value pairs used by the shell and programs to control behavior, paths, credentials, and configuration. This guide explains what they are, how to view and set them, how to persist them, and how to use them safely in scripts and services.

What are environment variables?

Environment variables are strings exported into a process's environment so that the process and its child processes can read them. They affect programs in many ways: PATH determines where executables are searched for, HOME points to the user’s home directory, LANG affects locale settings, and custom variables can enable feature toggles or provide configuration values.

Example: read a variable in the shell

$ echo $HOME
/home/alice

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

You can create short-lived variables for a single command:

$ TZ=UTC date
Mon Jan  1 12:00:00 UTC 2024

That TZ is visible to date (and its child processes) only for this invocation.

Viewing, listing, and common commands

You often need to list all environment variables or check a particular one. There are multiple commands and shells have built-ins that behave slightly differently.

Common ways to view environment variables:

  • printenv: prints environment variables (simple and common)
  • env: runs a command in a modified environment or lists env vars without arguments
  • set: in bash, lists shell variables and functions (more verbose)
  • export -p: lists exported variables (bash/zsh)
  • echo $VAR: shows one variable

Terminal examples:

$ printenv | head -n 20
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/home/alice
LANG=en_US.UTF-8
...

List only variables matching a pattern:

$ env | grep -i proxy
http_proxy=http://proxy.example:3128
HTTP_PROXY=http://proxy.example:3128

Exported vs shell-local variables:

$ MYVAR=hello
$ python -c 'import os; print(os.environ.get("MYVAR"))'
None

$ export MYVAR=hello
$ python -c 'import os; print(os.environ.get("MYVAR"))'
hello

Setting and exporting variables (temporary and persistent)

Temporary (current shell / single command) vs persistent (across sessions). A plain assignment sets a shell variable; export turns it into an environment variable visible to child processes.

Set for current shell only:

$ FOO=bar
$ echo $FOO
bar

Set and export for children:

$ export FOO=bar
$ bash -c 'echo $FOO'
bar

Set for a single command:

$ FOO=bar python -c 'import os; print(os.environ.get("FOO"))'
bar
# FOO is not present afterwards
$ echo $FOO

Make variables persistent (common places):

  • ~/.bashrc or ~/.bash_profile or ~/.profile for interactive login/non-login shells
  • /etc/environment for system-wide simple key=value pairs (not shell expansions)
  • systemd service files (Environment= or EnvironmentFile=)
  • For non-shell apps, configuration files or secret managers are better

Example: add to ~/.bashrc

# ~/.bashrc
export EDITOR=vim
export PATH="$HOME/bin:$PATH"

After editing, apply:

$ source ~/.bashrc

Example: system-wide (/etc/environment)

# /etc/environment
LANG="en_US.UTF-8"
JAVA_HOME="/usr/lib/jvm/java-17-openjdk"

Note: /etc/environment does not support shell expansions like $HOME.

Using environment variables in scripts and tools

Scripts rely heavily on environment variables to be portable and configurable. Use parameter expansion to provide defaults and fail-fast behavior.

Read a variable with a default:

#!/bin/bash
# myscript.sh
PORT=${PORT:-8080}    # default to 8080 if PORT is unset or empty
echo "Starting service on port $PORT"

Fail if a required variable is missing:

#!/bin/bash
: "${DATABASE_URL:?DATABASE_URL must be set}"
# script exits with a message if DATABASE_URL is not defined

Using environment variables with systemd:

# /etc/systemd/system/myapp.service
[Service]
Environment="APP_ENV=production" "PORT=8000"
EnvironmentFile=/etc/myapp/envfile
ExecStart=/usr/bin/myapp

Substitute variables in config templates (example using envsubst):

$ cat config.template
listen ${PORT}
$ export PORT=8080
$ envsubst < config.template > config.conf
$ cat config.conf
listen 8080

Security tip: avoid putting secrets into world-readable dotfiles. Use restricted files (600) or secret managers.

Commands table

Below is a quick reference table for commonly used commands related to environment variables.

Command Purpose Example
env List environment variables or run a command in modified env env | grep HOME
printenv Print environment variables (single or all) printenv PATH
export Make a shell variable part of the environment export EDITOR=vim
unset Remove a variable from the environment/shell unset FOO
set In bash, list shell variables and functions set | head
source (.) Reload a file in the current shell source ~/.bashrc
envsubst Substitute env vars in input envsubst < template > out
grep Filter listings for patterns env | grep -i proxy

Example terminal usage:

$ export MYAPP_DEBUG=1
$ env | grep MYAPP
MYAPP_DEBUG=1

$ unset MYAPP_DEBUG
$ echo $MYAPP_DEBUG

Common Pitfalls

  • Mixing shell-local and exported variables: setting VAR=value does not make it available to child processes unless you export it. This frequently causes programs to see a missing value.
  • Putting secrets in plain, world-readable files: storing API keys in ~/.bashrc or /etc/environment without proper permissions can leak credentials. Use secure storage or restrict file permissions (chmod 600).
  • Expecting shell expansions in files that don't support them: /etc/environment is read by PAM and does not perform $HOME or command substitutions. If you rely on expansions, use shell rc files (~/.bashrc) or manage with systemd EnvironmentFile.

Example showing first pitfall:

$ SECRET=topsecret
$ bash -c 'echo $SECRET'
# nothing printed because SECRET wasn't exported

$ export SECRET=topsecret
$ bash -c 'echo $SECRET'
topsecret

Next Steps

  • Try practical experiments: use printenv, env, export, and unset in an interactive shell and observe child process visibility.
  • Persist a simple variable (e.g., EDITOR) in ~/.bashrc, source it, and verify it appears for new shells and child processes.
  • Learn about secure secret management (e.g., systemd secrets, HashiCorp Vault, or cloud provider secret stores) before placing sensitive data in environment variables.

This overview should give you the basics to view, set, and use environment variables in Linux safely and effectively.

👉 Explore more IT books and guides at dargslan.com.