Skip to content
Ameen Abozaid
PublishedBEG-006-L05

Environment variables in the shell

  • Lesson 5 of 8
  • 11 min read
  • Beginner
On This Lesson 11 topics

Lesson Overview

In Module 5 you met PATH, an environment variable: a named piece of text that the operating system and your programs can read. You printed it and learned that a missing entry causes "command not found". You may have changed it through system settings.

This lesson looks at the same idea from inside the shell. You will read a variable, create your own, see exactly how long it lasts, and learn why a variable you set in one terminal is invisible in another. With the literal-assistant picture: an environment variable is a sticky note on the assistant's desk. Any program the assistant starts can read the note, but notes on one assistant's desk do not appear on another's.

This lesson builds on "Environment variables and PATH" in Module 5 and on the previous lessons of this module (running commands, quoting, and echo). You will use echo to print a variable, and you will run a command in a fresh child shell to prove what it can see.

The syntax is different in Bash and PowerShell, so every step is shown both ways. Where a feature depends on a version or system, the lesson says so.

Learning Objectives

By the end of this lesson you will be able to:

  • Read an environment variable in Bash and in PowerShell.
  • Set a variable for the current session in both shells.
  • Explain what export adds in Bash.
  • List all variables and remove one.
  • Explain why a variable disappears when the terminal closes.
  • Add a folder to PATH for one session, without replacing the old value.
  • Name where permanent variables are usually stored, and why secrets should not live in code.

Written Explanation

Recap: what an environment variable is

An environment variable is a name and a text value, such as COURSE with the value java. Microsoft's PowerShell documentation describes them as always strings, and as inherited by child processes: when a program starts another program, the child receives a copy of the parent's variables at that moment.

You do not have to remember the technical words. Remember the effect: set it in a terminal, and programs started from that terminal can see it.

Reading a variable

ShellRead variable COURSERead PATH
Bashecho $COURSEecho $PATH
PowerShell$env:COURSE$env:PATH

In Bash, the $ in front of a name means "the value of". In PowerShell, $env: is the prefix for environment variables. If the variable does not exist, Bash prints an empty line and PowerShell prints nothing.

Variable names are case-sensitive in Bash and, according to Microsoft, in PowerShell on macOS and Linux, so PATH and path differ there. On Windows they do not. Convention uses capitals for environment variables, and you should too.

Setting a variable

Bash

text
$ export COURSE=java
$ echo $COURSE
java

Rules: no spaces around =. export COURSE = java fails. Quote a value that contains spaces: export TITLE="Java for backend".

PowerShell

text
PS> $env:COURSE = "java"
PS> $env:COURSE
java

In PowerShell, spaces around = are fine and quotes are normal.

What export does in Bash

In Bash, you can create a plain shell variable with COURSE=java (no export). Your shell can use it, but programs it starts will not see it. Adding export marks the variable to be passed on to child processes, making it an environment variable.

You can prove it with a child shell:

text
$ COURSE=java
$ bash -c 'echo "child sees: $COURSE"'
child sees:
$ export COURSE
$ bash -c 'echo "child sees: $COURSE"'
child sees: java

The single quotes matter. They stop your current shell from expanding $COURSE itself, so the child does the reading. This behavior is long-standing Bash practice; the manual page I read mentions that export assigns an attribute to variables, but I did not verify the child-process detail in a source in this session, so try the demo on your own computer.

PowerShell has no separate step: $env:COURSE = "java" writes straight into the environment, so child programs started from that session see it. You can check with a child PowerShell (the program is pwsh for PowerShell 7 and powershell for Windows PowerShell):

text
PS> pwsh -NoProfile -Command '$env:COURSE'
java

Single quotes keep $env:COURSE for the child to evaluate.

Listing and removing variables

  • Bash: printenv lists all environment variables. printenv COURSE prints one value. unset COURSE removes the variable from the current shell.
  • PowerShell: Get-ChildItem Env: lists them all, and Get-ChildItem Env:COURSE shows one. Remove one with Remove-Item Env:COURSE. Microsoft's page also says that from PowerShell 7.5 on, assigning $null ($env:COURSE = $null) removes it.

Output can be long. Pipe it into a filter from Lesson 4: printenv | grep COURSE, or Get-ChildItem Env: | Select-String COURSE.

How long does it last?

Only until you close that terminal, or more exactly until that shell session ends. Microsoft's documentation states that changes you make in PowerShell affect only the current session. In both shells, a variable set this way is invisible in a different terminal window, and gone when you reopen.

The reason is that each shell has its own copy. A new terminal gets its variables fresh from the system and your configuration files, not from the terminal you closed.

Making a variable permanent

Do not do it yet, but know where it lives:

  • Bash and zsh: a line such as export COURSE=java in a startup file such as ~/.bashrc or ~/.zshrc. Microsoft's page mentions those two files for non-login shells. Which file applies depends on the shell and how it was started, so check your system's documentation.
  • Windows: the Environment Variables dialog (reached through the system settings), which stores a value for your user or for the whole machine. PowerShell can also write a user-level value with [Environment]::SetEnvironmentVariable('COURSE','java','User'). Microsoft's page documents that method and the scopes. After a permanent change, open a new terminal to see it, exactly as in Module 5.

Adding a folder to PATH for one session

PATH is a list of folders separated by : in Bash and on macOS and Linux, and by ; on Windows (Microsoft's page confirms both). To add a folder without losing the existing ones, put the old value inside the new one:

text
$ export PATH="$HOME/tools:$PATH"
PS> $env:PATH += ";C:\Tools"

The Bash line puts ~/tools first and keeps everything else. The PowerShell line appends C:\Tools to the end, as in Microsoft's own example; on macOS or Linux use : instead of ;. The classic error is replacing PATH (export PATH=$HOME/tools), which removes everything else. Almost every command then stops being found, until you close the terminal.

Quoting and expansion in Bash

  • echo "$COURSE" and echo $COURSE print the value. Double quotes allow expansion.
  • echo '$COURSE' prints the literal text $COURSE. Single quotes block expansion.

In PowerShell, double-quoted strings also expand variables ("Course: $env:COURSE"), and single-quoted strings do not.

Examples

Example 1: Set, read, remove (simple)

Bash:

text
$ export GREETING="hello there"
$ echo $GREETING
hello there
$ unset GREETING
$ echo $GREETING

PowerShell:

text
PS> $env:GREETING = "hello there"
PS> $env:GREETING
hello there
PS> Remove-Item Env:GREETING
PS> $env:GREETING

After removal there is nothing to print. The variable lived only in this one terminal, and now it is gone from it too.

Example 2: The vanished variable (practical)

You set $env:COURSE = "java" in one terminal and see it print java. You open a second terminal window and type $env:COURSE. It prints nothing.

Nothing is broken. The second window is a separate shell session with its own copy of the environment, built from the system settings, not from the first window. The same happens in Bash. To make a variable available everywhere, store it permanently, then open a new terminal.

Example 3: A safe PATH experiment (realistic)

Imagine a small program, hello.sh, in ~/tools. Typing hello.sh gives "command not found", because ~/tools is not on PATH.

text
$ export PATH="$HOME/tools:$PATH"
$ hello.sh

The shell now searches ~/tools first. (If you get "Permission denied", Lesson 6 explains why.) Close the terminal and reopen it, and the line is no longer in effect. That temporary effect is what makes this safe for experiments. On Windows, the same idea is $env:PATH += ";C:\Tools"; a program in C:\Tools can then be run by name from that session.

Backend Insight

Backend programs read configuration from the environment. A service started on a server may find where its database is in a variable named like DATABASE_URL, and which mode it runs in (testing or production) in another. The same program, started with different variables, behaves differently with no code change. This is why the same build can run on a laptop and in production.

It also keeps secrets out of source code. Passwords and keys are set in the environment (or in a secrets system) rather than written into files that get shared with a team. Java programs can read environment variables too, which you will see later in your Java learning.

Be careful what you print. Running printenv in front of colleagues or pasting its output into a bug report can leak secrets.

Common Mistakes

Mistake 1: Spaces around = in Bash

  • Incorrect: export COURSE = java
  • Correct: export COURSE=java

Mistake 2: Mixing the syntaxes

$env:COURSE is PowerShell only. In Bash it prints something odd or an empty line. export COURSE=java is Bash only, and PowerShell will report that export is not recognised.

Mistake 3: Expecting the variable in another terminal or after closing

A session variable lives and dies with that shell. For anything permanent, use a startup file or the system settings, then open a new terminal.

Mistake 4: Replacing PATH instead of adding to it

export PATH=$HOME/tools loses the old list. Always include the old value: export PATH="$HOME/tools:$PATH".

Exercises

Try each exercise yourself before opening the solutions.

Level A: Foundation

A1. Which command prints the variable LEVEL in Bash? Which in PowerShell?

Show solution A1

A1. Bash: echo $LEVEL. PowerShell: $env:LEVEL.

A2. What does export add in Bash?

Show solution A2

A2. It marks the variable to be passed to programs the shell starts (child processes), turning a plain shell variable into an environment variable.

A3. True or false: a variable set with $env:LEVEL = "beginner" is still there after you close the terminal. Why?

Show solution A3

A3. False. A variable set in the shell lasts only for that session, and a new terminal starts without it.

Level B: Application

B1. In your own shell, set LEVEL to beginner, print it, and then remove it. Write each command and its output.

Show solution B1

B1. Bash: export LEVEL=beginner, echo $LEVEL prints beginner, unset LEVEL, echo $LEVEL prints an empty line. PowerShell: $env:LEVEL = "beginner", $env:LEVEL prints beginner, Remove-Item Env:LEVEL, $env:LEVEL prints nothing.

B2. In Bash, show that a variable without export is not visible to a child shell, and that it is visible after export. Write the commands.

Show solution B2

B2. LEVEL=beginner, then bash -c 'echo "child sees: $LEVEL"' prints an empty value. After export LEVEL, the same command prints child sees: beginner.

B3. Find which of these lines would break your session, and say why: export PATH="$HOME/bin:$PATH" and export PATH=$HOME/bin.

Show solution B3

B3. The second line, export PATH=$HOME/bin, replaces the whole list so most commands are no longer found. The first line keeps the old list by including $PATH.

Level C: Challenge

C1. In PowerShell, set NAME to Ana Smith (with a space) and print Hello, Ana Smith using the variable inside a double-quoted string. Show the command.

Show solution C1

C1. $env:NAME = "Ana Smith" then "Hello, $env:NAME". Double quotes expand the variable.

C2. A teammate sets DB_PASSWORD in their terminal, runs the service, and it works. Tomorrow it fails with "password not set". Explain why, and suggest two safer places to keep the setting.

Show solution C2

C2. The variable lived only in yesterday's terminal session, which ended. Safer places: a startup file or system environment setting for their account (and a secrets tool for real production systems), rather than typing the secret by hand each time or putting it in code.

Mini Challenge

Create a tiny "shell notes" demonstration, in the shell you use:

  1. Set a variable PROJECT to the name of a made-up project and print it.
  2. Show it is visible to a child shell (bash -c or the PowerShell child command).
  3. Add a folder of your choice to PATH for the session, and print PATH to prove the folder is on it.
  4. Close the terminal, open a new one, and show with a command that PROJECT is gone.

Check your work: your PATH change added to the old list rather than replacing it, and you did not print any secret.

Summary & Next Lesson

Key takeaways

  • An environment variable is a name and a text value that programs started from your shell can read.
  • Bash: read with $NAME, set with export NAME=value. PowerShell: read and set with $env:NAME.
  • Session variables last only until that shell session ends, and are not shared with other terminals.
  • Add to PATH, never replace it. Permanent settings go in a startup file or the system settings.
  • Backend programs take configuration and secrets from the environment, so the same code runs in different places.

Next lesson

You can now read and set variables. The next lesson, "Permissions basics", explains why a script you wrote may refuse to run, and how a file's permissions decide what can be done with it.

Self-check

  1. What does echo $COURSE print if COURSE was never set?
  2. How do you set a variable in PowerShell?
  3. Does export NAME=value survive closing the terminal?
  4. Why is export PATH=/tools dangerous?
  5. Why do backend programs read configuration from environment variables?
Show answers
  1. An empty line.
  2. $env:NAME = "value".
  3. No. It lasts only for that session.
  4. It replaces the existing list, so most commands can no longer be found.
  5. The same program can behave differently in each place without code changes, and secrets stay out of source files.

References

  • Microsoft Learn, about_Environment_Variables. Supports: $Env: reads and sets, variables are strings, inheritance by child processes, changes affecting only the current session, Remove-Item Env: and $null (PowerShell 7.5 and later) for removal, SetEnvironmentVariable with scopes, PATH separators on Windows and non-Windows, $Env:PATH += ';C:\Tools', case sensitivity on macOS and Linux, and ~/.bashrc and ~/.zshrc as shell startup files.
  • man7.org, bash(1) manual page. Supports: export assigns an attribute to variables, PATH is a colon-separated list of directories, and ~ expands to the home folder.
  • Not verified on an official page: that a non-exported Bash variable is invisible to child processes, the printenv, unset, and bash -c behaviors, which startup file applies in which situation, and that Java can read environment variables. The text marks the child-process detail as something to try yourself.

Practice

Apply this lesson with the module's lab, exercises and quiz.

Lab and exercises Quiz

Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.

Continue to next lesson

Type to search levels, phases, modules and lessons.