datarekha

Environment variables & PATH

Learn what environment variables are, how PATH controls where the shell finds commands, and why 'command not found' happens — and how to fix it.

8 min read Intermediate Command Line Lesson 11 of 14

What you'll learn

  • What environment variables are and how to read and set them
  • How PATH controls command resolution, left-to-right through directories
  • How to make changes persist across sessions using shell startup files

Before you start

What is an environment variable?

Every process on your computer runs inside an environment — a small table of key/value string pairs that the operating system hands to the process when it starts. These are called environment variables.

Programs read this table to configure themselves without needing command-line flags every time. Your text editor reads $EDITOR. Git reads $HOME. Servers read $PORT and $DATABASE_URL. The shell itself reads dozens of them.

Print your own home directory:

echo $HOME
/Users/alice

The $ prefix tells the shell to expand the variable — substitute its value before running the command.

To see the entire environment, use either of these:

env
printenv

Both dump every variable the current shell process inherited, one per line, in NAME=value format. The list is usually long — scroll up to browse it.

To look up a single variable:

printenv HOME
/Users/alice

Setting an environment variable

Use export to create or update a variable and make it visible to child processes (programs you launch from the shell):

export GREETING="hello world"
echo $GREETING
hello world

Three things to memorize:

  1. No spaces around =. export NAME=value works. export NAME = value is a syntax error — the shell interprets the spaces as argument boundaries.
  2. The value is just a string. Numbers, paths, JSON — all strings.
  3. export is required if you want child processes to see the variable. A bare NAME=value assignment stays local to the current shell.

What is PATH?

$PATH is an environment variable with one job: it is a colon-separated list of directory paths that the shell searches, in order, when you type a command name.

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

When you type python3, the shell does not search the whole disk. It walks through each directory in $PATH, left to right, and checks whether a file named python3 exists and is executable. The first match wins.

You type:python31st dir/usr/local/binpython3 ✓2nd dir (skipped)/usr/binpython3 ✗3rd dir (skipped)/binpython3 ✗… more dirs/sbinpython3 ✗First match wins/usr/local/bin/python3
The shell walks PATH left-to-right and runs the first matching executable it finds. If none match, you get “command not found.”

“Command not found” means the shell walked every directory in your $PATH and found nothing. The tool is installed somewhere — just not in any of those directories.

Inspecting command resolution

Two commands let you see exactly where a command is found:

which python3
/usr/local/bin/python3
type python3
python3 is /usr/local/bin/python3

type is slightly more informative — it also tells you when a name is a shell builtin, a function, or an alias rather than an executable file.

Adding a directory to PATH

Say you have scripts in ~/bin and you want to run them by name. Add that directory to your PATH:

export PATH="$HOME/bin:$PATH"

Break this down:

  • $HOME/bin — the new directory you are adding
  • : — the colon separator
  • $PATH — the existing value, preserved

The new directory goes on the left, so it takes precedence over anything with the same name in later directories.

Making changes persist: startup files

Environment variables you export in a terminal session disappear when that session closes. To make them permanent, add the export line to your shell’s startup file (also called an rc file — “rc” stands for “run commands”).

ShellFile to edit
zsh (macOS default)~/.zshrc
bash (Linux default, older macOS)~/.bashrc and/or ~/.bash_profile

Open ~/.zshrc in any editor and add your export at the bottom:

export PATH="$HOME/bin:$PATH"
export EDITOR="vim"

Save the file. The change takes effect in every new shell session. To pick it up in the current session without opening a new tab, source the file:

source ~/.zshrc

Sourcing means “read this file and run every line as if I had typed it myself.” The word source can also be written as a single dot: . ~/.zshrc.

.env files for project secrets

For project-specific settings — API keys, database URLs, feature flags — teams conventionally use a .env file at the project root:

DATABASE_URL=postgres://localhost/myapp
API_KEY=abc123
DEBUG=true

This file is never committed to version control (add .env to your .gitignore). To load it into your current shell:

source .env

Many frameworks (Python python-dotenv, Node dotenv) load .env automatically when your app starts, so you often do not need to source it manually.

Quick reference

echo $HOME               # print one variable
env                      # print all variables
printenv VARNAME         # print one variable (no $ prefix needed)

export NAME=value        # set a variable (no spaces around =)
export PATH="~/bin:$PATH"  # prepend a directory to PATH

which cmd                # show the full path of a command
type cmd                 # show how the shell resolves a name

source ~/.zshrc          # reload startup file in current session

Quick check

0/3
Q1You run `export PATH="/opt/mytool/bin"`. What is the most likely result?
Q2You add `export EDITOR=nano` to `~/.zshrc` and save the file. You open a new terminal tab. What do you need to do to make the current tab also use the new setting?
Q3A teammate gives you a Python script that needs the environment variable `API_KEY` set to `secret`. They will run it on a Linux server with bash. Where should they put the export line so it is available every time they log in — without hard-coding the secret in the script itself?

Sign in to track your progress

Completed lessons, your XP, level, and streak save to your account — it's free and takes a few seconds.

Explore further

Glossary terms

Related lessons

Skip to content