19 19. Environment Variables
Programs often need information that shouldn’t be typed into their code: where your home folder is, which folders contain commands, or a secret password for an online service. The shell keeps this kind of information in variables. This page explains shell variables and environment variables, why they are used, and how to make them permanent.
19.1 Shell variables
A variable is a name that holds a value. It’s like naming a cell in Excel (say, calling cell B2 “TaxRate”) so you can use the name instead of the value.
Create a variable with name=value, and read it by putting a $ in front of its name:
course="AI Assisted Development"
echo $course
echo "I am taking $course"Output:
AI Assisted Development
I am taking AI Assisted Development
The value needs quotes because it contains spaces. Inside the double quotes in the last command, the shell replaced $course with the variable’s value.
When the variable name touches other text, put the name in curly braces, ${name}, to show where the name ends:
file=report
echo "$file_2026.txt"
echo "${file}_2026.txt"Output:
.txt
report_2026.txt
In the first echo, the shell looked for a variable named file_2026 (underscores and digits can be part of a name). There is no such variable, so it was replaced with nothing.
- No spaces around
=.name = Mariadoesn’t create a variable: the shell thinksnameis a command and reports an error (command not found: nameon a Mac,name: command not foundin Git Bash). - Quote values that contain spaces.
name=Maria Lopezfails withcommand not foundforLopez. Usename="Maria Lopez". - Names are case-sensitive.
$Nameand$nameare different variables. - Typos fail silently. A variable that doesn’t exist is simply empty, so
echo $corse(instead of$course) prints an empty line instead of an error.
19.2 Environment variables and export
Every program on your computer runs with a set of named values called its environment. Environment variables are variables that the shell passes on to every program it starts.
A variable you create with name=value is a shell variable: only the shell itself knows about it. The export command turns it into an environment variable, so that the programs you start can see it too.
The printenv command is a separate program that prints the value of an environment variable. Watch what it sees before and after export:
city="Boston"
printenv city
export city
printenv cityOutput:
Boston
The first printenv city printed nothing, because city was only a shell variable. After export, the second one printed Boston.
Usually you create and export a variable in one step, and by convention environment variable names are written in UPPERCASE:
export CITY="Boston"To remove a variable, use unset CITY.
- Every running program is a process. When your shell starts a program, that program becomes a child process of the shell, and it receives a copy of the shell’s environment variables (but none of its plain shell variables).
- The copy only goes one way. A child process can change its own copy, but it can never change the variables of the shell that started it. (That’s why a script that sets a variable doesn’t change your terminal, unless you run the script with
source, which runs its lines in your current shell.) echo $cityworks for both kinds of variables, because the shell replaces$citybeforeechoeven runs. To see whether a variable was exported, useprintenv cityor look for it in the output ofenv.- You can also set an environment variable for one single command by writing it in front of the command:
GREETING=hello printenv GREETINGprintshello, but afterwardsprintenv GREETINGprints nothing.
19.3 Why environment variables are used
- To configure a program without changing its code. The same program can behave differently depending on its environment. A web app might read a variable such as
DATABASE_URLand connect to a practice database on your laptop (“development”) but to the real customer database on the server (“production”). - To keep secrets out of code. Passwords and API keys (secret codes that let your program use an online service, such as a payment or AI service) should never be typed into code, which may end up on GitHub for everyone to see. Instead the code reads them from the environment, for example
os.environ["WEATHER_API_KEY"]in Python orprocess.env.WEATHER_API_KEYin JavaScript. - To describe the computer and the user. Programs find your home folder through
HOME, and the shell finds commands throughPATH.
19.4 Common environment variables
| Variable | What it holds |
|---|---|
HOME |
your home directory |
USER |
your user name (in Git Bash: USERNAME) |
PWD |
the current working directory (it changes every time you cd) |
SHELL |
your default shell, the one a new terminal window starts |
PATH |
the folders the shell searches for commands (see below) |
LANG |
your language and character set, for example en_US.UTF-8 |
Try a few of them:
echo $HOME
echo $USER
echo $SHELLOutput:
/Users/maria
maria
/bin/zsh
echo $HOME
echo $USERNAME
echo $SHELLOutput:
/c/Users/sam
sam
/usr/bin/bash
In Git Bash, echo $USER usually prints an empty line, because Windows stores your user name in a variable called USERNAME. (The whoami command works on both systems.)
To list all your environment variables, type env (or printenv with no arguments). The list is long; most of the entries are used by programs behind the scenes.
19.5 PATH: how the shell finds commands
When you type a command such as ls, the shell doesn’t search your whole computer for it. It looks only in the folders listed in the PATH variable, in order, and runs the first program named ls that it finds.
echo $PATHOutput (something like this on a Mac; yours will probably be longer):
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
The folders are separated by colons (:). In Git Bash the list is longer and includes Windows folders, written in the /c/... style.
The which command tells you where a command was found:
which lsOutput (Mac; in Git Bash it’s /usr/bin/ls):
/bin/ls
When you see command not found, there are three usual reasons: you made a typo, the program isn’t installed, or it is installed in a folder that isn’t on your PATH. That last one often happens right after installing a new tool, which is why installation instructions sometimes say “add this folder to your PATH”. (You will see this again in Installing Claude Code.)
To add a folder, put it in front of the existing list:
export PATH="$HOME/bin:$PATH"Read it as: “the new PATH is my bin folder, a colon, and then the old PATH.”
$PATH
export PATH="$HOME/bin" (without :$PATH at the end) replaces the whole list. After that, even ls gives “command not found”. If this happens, close the terminal window and open a new one; the change was only temporary.
Notice that your current folder is not on the PATH. That’s why you have to type ./ in front of a script in the current folder to run it (see Bash Scripts).
19.6 Making variables permanent
Variables that you set at the prompt disappear when you close the terminal window. Every new terminal window starts by running a startup file in your home folder, so to keep a setting, put its export line in that file.
For example, many programs check the EDITOR variable to decide which text editor to open. To set it permanently, open your startup file in nano (see below), add the line export EDITOR="nano" at the bottom, press Ctrl+O and Enter to save, and Ctrl+X to exit. Then open a new terminal window, or load the file into the current one with source:
zsh reads ~/.zshrc every time you open a new Terminal window. Open it with:
nano ~/.zshrcAfter saving and exiting, load it with:
source ~/.zshrcPut your settings in ~/.bashrc. Open it with:
nano ~/.bashrcAfter saving and exiting, load it with:
source ~/.bashrcWhen Git Bash starts, it actually reads ~/.bash_profile. If you have a ~/.bashrc but no ~/.bash_profile, the next new Git Bash window prints a WARNING about this and creates a ~/.bash_profile that loads your ~/.bashrc. That is expected, and it happens only once.
source runs the lines of a file in your current shell, so the new setting takes effect right away.
You can also add a line without opening an editor, using >> from Writing to Files (use ~/.bashrc instead of ~/.zshrc in Git Bash):
echo 'export EDITOR="nano"' >> ~/.zshrcUse >>, never >, which would erase everything else in the file. The single quotes make sure the line is written exactly as typed. That matters as soon as a line contains $, as in export PATH="$HOME/bin:$PATH"; the next page, Single Quotes vs. Double Quotes, explains why.
19.7 API keys, .env files, and secrets
Projects usually keep their settings and keys in a text file named .env in the project folder, one NAME=value per line:
DATABASE_URL=postgres://localhost/club_app
WEATHER_API_KEY=paste-your-key-here
Many frameworks and tools load this file into the environment automatically when the app starts. Because a .env file holds secrets, it must never be committed to Git: see .gitignore and Keeping Secrets Out of Git and APIs, API Keys, and Third-Party Services.
- Never paste a real API key into code, a chat, an AI prompt, a screenshot, or a shared document.
- Don’t print a key with
echowhile your screen is shared or recorded. - Commands you type are saved in your shell’s history file, so a key typed at the prompt ends up stored on disk in plain text.
- If a key leaks, revoke it on the service’s website and create a new one.
19.7.1 Example: Claude Code and ANTHROPIC_API_KEY
As of Oct 6, 2026 · Official docs: Environment variables
Claude Code reads many environment variables; its documentation lists them all. One of them shows why it pays to know what’s in your environment: ANTHROPIC_API_KEY. If this variable is set, Claude Code uses that API key instead of your Claude subscription, even if you are logged in, so your usage is billed to the API account that owns the key. (In an interactive session, it asks you once to approve the key before using it.) If you meant to use your subscription, remove the variable with:
unset ANTHROPIC_API_KEYAlso delete any line that sets it from your startup file (~/.zshrc or ~/.bashrc), or it will come back in the next terminal window.
Practice Questions
Easy
Question 1 · Short answer
What is a variable in the shell?
Question 2 · Multiple choice
Which command correctly creates a variable named name with the value Maria?
name = Marianame=Maria$name=Marianame == Maria
Question 3 · True or false
A variable you create at the prompt is still there after you close the terminal window and open a new one.
Question 4 · Matching
Match each environment variable with what it holds.
| Variable | What it holds | |
|---|---|---|
1. HOME |
A. the folders the shell searches for commands | |
2. PATH |
B. the current working directory | |
3. PWD |
C. your home directory | |
4. SHELL |
D. the path to your default shell program |
Question 5 · Short answer
What does the export command do?
Question 6 · Multiple choice
Which command lists all of your environment variables?
lsenvechopwd
Medium
Question 7 · Predict the output
What does this print, and how would you fix it so it prints I like apples?
fruit=apple
echo "I like $fruits"Question 8 · Write the command
Create a variable project with the value budget app, then use it to print Working on budget app.
Question 9 · Predict the output
What does each printenv command print? Explain the difference.
color="blue"
printenv color
export color
printenv colorQuestion 10 · Short answer
Maria types which python3 and sees /usr/bin/python3. What does this tell her?
Question 11 · Scenario
Sam installs a new command-line tool, but typing its name gives command not found. Give three possible reasons.
Question 12 · Write the command
Maria (Mac) wants export EDITOR="nano" to apply in every new Terminal window, and she wants it to take effect in her current window too. Write two commands that do this without opening an editor.
Question 13 · Short answer
Give two reasons why programs usually read API keys from environment variables instead of having the keys typed into the code.
Question 14 · Write the command
In Git Bash, echo $USER prints an empty line for Sam. Give two commands that print his user name.
Hard
Question 15 · Find the bug
Maria wanted to add her ~/bin folder to her PATH and typed:
export PATH="$HOME/bin"Now even ls says command not found. What went wrong, how does she recover, and what should she have typed?
Question 16 · Scenario
Sam opened ~/.bashrc in nano, added export GREETING="hi", saved, and exited. In the same window, echo $GREETING prints an empty line.
- Why, and what two things could he do?
- The next time he opens Git Bash, he sees a WARNING about
~/.bash_profile. Should he worry?
Question 17 · Scenario
A student with a Claude Pro subscription notices charges on an API account she set up last semester for another class. Her ~/.zshrc contains a line that exports ANTHROPIC_API_KEY. Explain what is probably happening and how she should fix it.
Question 18 · Long answer
A web app reads the environment variable DATABASE_URL to decide which database to connect to. Explain how this lets the same code run safely on a developer’s laptop and on the production server.
Question 19 · Compare
After city="Boston" (without export), echo $city prints Boston, but printenv city prints nothing. Explain why.
Question 20 · Ordering
Put these steps in order to permanently add ~/bin to the PATH on a Mac:
- Run
source ~/.zshrc(or open a new Terminal window). - Open the startup file with
nano ~/.zshrc. - Check the result with
echo $PATH. - Add the line
export PATH="$HOME/bin:$PATH"at the bottom of the file. - Save with
Ctrl+O,Enter, and exit withCtrl+X.