PLAINFINCH learn by building

Environment variables

You will look at the settings your shell keeps, make your own named values, and use them inside commands.

What is an environment variable?

An environment variable is a named piece of text that your shell keeps and hands to every program it starts. HOME holds your home folder, USER your account name, PATH the list of folders the shell searches for commands, and EDITOR the editor programs should open when they need you to type something.

Programs read these instead of guessing. cd with no folder goes to $HOME. Git opens $EDITOR for a commit message. Web apps read settings such as a database address or an API key from variables so the same code can run on your laptop and on a server with different values.

Names are case-sensitive and by convention written in capitals for exported settings. They may contain letters, digits and underscores, and can’t start with a digit. WALK_DAY is fine; WALK-DAY and WALK DAY are not names at all.

How do you see a variable’s value?

Put a $ in front of the name. The shell replaces $HOME with its value before the command runs, so echo $HOME prints /home/you. To list every exported variable, run env (or printenv, which does the same, and printenv HOME prints one).

$ echo $HOME
/home/you
$ env
EDITOR=nano
HOME=/home/you
HOSTNAME=laptop
LANG=en_GB.UTF-8
PATH=/usr/local/bin:/usr/bin:/bin
PWD=/home/you/bird-club
SHELL=/bin/bash
USER=you

What happens when a variable isn’t set?

A real shell has more variables than this list, including TERM and SHLVL; the practice terminal keeps only the useful few. The System view on the right shows the same list and updates as you change it.

An unset variable expands to nothing, with no error. echo $WALKDAY with a typo prints an empty line. That silence is the most common source of trouble with variables: a script that refers to $BACKUP_DIR when it was never set may end up working in the wrong folder. When something prints blank, check the spelling with env.

How do you set a variable?

Write the name, an equals sign and the value, with no spaces around =: CLUB=Riverside. If you put spaces, as in CLUB = Riverside, the shell thinks CLUB is a command and tries to run it with = and Riverside as arguments.

If the value has spaces, quote it: CLUB="Riverside Bird Club". Without quotes, real bash takes CLUB=Riverside as a setting for one command and then tries to run Bird as that command, giving bash: Bird: command not found. The practice terminal says the same. The cure is quotes.

A variable set this way lives only in the current shell. Close the terminal and it’s gone. To keep a setting for every new terminal, add the line to your ~/.bashrc, which the lesson on aliases and settings files covers. unset CLUB removes a variable straight away.

What is the difference between NAME=value and export?

CLUB="Riverside Bird Club" creates a shell variable. Your shell can use it, so echo $CLUB works, but it isn’t passed to programs you start. export CLUB marks it for export, and from then on every program and script started from this shell gets a copy. You can do both in one go: export CLUB="Riverside Bird Club".

In a real terminal the difference shows when you run a script. With a plain CLUB=..., ./notice.sh prints an empty name, because the script runs as a separate program with its own copy of the environment. After export, it prints the name. The practice terminal behaves the same way, so you can try both. env is the quick test: if a variable isn’t in env, a program won’t see it.

Exporting only goes one way. A script can’t set a variable in the shell that started it, because it gets a copy. That’s why setup files are read with source ~/.bashrc rather than run as ./.bashrc. For a single command you can also write WALK_DAY=Saturday ./notice.sh, which sets the variable for that one program and leaves your shell unchanged.

FigureThe shell holds CLUB as a plain shell variable and WALK_DAY as exported. Running notice.sh copies only WALK_DAY across, so the script prints a blank club name before walk on Sunday.The shell holds CLUB as a plain shell variable and WALK_DAY as exported. Running notice.sh copies only WALK_DAY across, so the script prints a blank club name before walk on Sunday.
Only exported variables travel to the programs you start. Export CLUB too and the name appears before the colon.

How do quotes change what a variable does?

Double quotes let the shell expand variables inside them and keep spaces together. Single quotes stop all expansion and keep the text exactly as typed. The difference shows clearly with echo:

$ export CLUB="Riverside Bird Club"
$ echo "Welcome to $CLUB"
Welcome to Riverside Bird Club
$ echo 'Welcome to $CLUB'
Welcome to $CLUB
$ echo ${CLUB}s
Riverside Bird Clubs

When do you need braces around a name?

The braces in ${CLUB}s mark where the name ends. Without them, $CLUBs asks for a variable called CLUBs, which doesn’t exist, and prints nothing. Use braces whenever letters, digits or underscores follow straight after the name, as in ${WALK_DAY}_walk.txt.

As a habit, put double quotes around every variable you use in a command: cp sightings.txt "$HOME/backup", cd "$PROJECT_DIR". If the value contains a space, the unquoted version splits into two arguments and the command goes wrong in ways that can be hard to spot, sometimes copying to or deleting the wrong thing.

How do you use variables in commands?

Anywhere you’d type text, you can type a variable. cd $HOME/bird-club works from any folder. ls "$HOME" lists your home folder. echo "Report for $USER on $(date)" mixes a variable with the output of a command. mkdir "$HOME/walks-$WALK_DAY" makes a folder called walks-Sunday.

Variables are also how you keep secrets out of files you share. Rather than writing a password into a script, the script reads $DB_PASSWORD, and each computer sets its own. Be careful printing them: env shows every value on screen, so don’t run it while sharing your screen or paste its output into a chat or an AI assistant if you’ve set keys.

What do AI-suggested commands get wrong with variables?

Watch for spaces around =, which assistants occasionally add when writing for readability. Check that values with spaces are quoted and that variables in paths are inside double quotes. Look out for export lines written for one shell and pasted into another: Windows PowerShell uses $env:CLUB = "..." and the old Command Prompt uses set CLUB=..., neither of which works in bash. On a Mac the default shell is zsh, which handles export and $NAME the same way for everything here, but its settings file is ~/.zshrc, not ~/.bashrc.

Finally, an AI answer that says “set your API key with export API_KEY=...” is fine for one session, but the key then sits in your shell history. Many people start the line with a space, which bash can be set to leave out of history, or store keys in a .env file with permissions of 600.

Field notes

  • An environment variable is a named piece of text that programs can read.
  • Put $ before a name to use its value, as in echo $HOME.
  • Set a value with no spaces around =, and quote values with spaces.
  • export passes a variable on to the programs you start.

Easy to get wrong

With spaces the shell treats CLUB as a command name and fails with command not found. Assignments have no spaces around =.

Without quotes the value stops at the first space, and Bird and Club become extra words that export tries to treat as names.

Single quotes print $CLUB as plain text. Double quotes put in the value.

A variable that isn’t exported stays in your shell, so the script sees an empty value.

Questions people ask

Why does my variable disappear when I open a new terminal?

Variables live only in the shell where you set them. Add the export line to ~/.bashrc (or ~/.zshrc on a Mac) so every new terminal sets it.

What is the difference between env and printenv?

With no arguments both list exported variables. printenv NAME prints one value without the name, which is handy in scripts.

How do I see shell variables that aren’t exported?

set lists everything, including functions, which is long. In practice echo $NAME is the quickest way to check one.

Is PATH an environment variable too?

Yes, and the most important one. It decides which programs run when you type a name. The next lesson covers it.

Keep going