Learn › Linux Foundations › Bash Shell Environment
variables - a hands-on Linux lab on a real virtual machine.
Two kinds of variable, one lesson. A plain shell variable is private to the shell you are in; an environment variable is one you exported, so child programs inherit it. Set with name=value and no spaces, read with $name and ${name}, prove the split with bash -c, and cross the border with export. Built-in values like $HOME vary per machine, so the drills teach the moves.
Type this into a shell: name=alice. Nothing prints. The shell just accepts it and gives you a fresh prompt.
Now type echo $name and it prints alice. The shell remembered. You handed it a value and it held onto it under a name you chose.
But there is a catch that trips up nearly everyone. Ask a program you launch from inside that same shell to print name, and it comes back blank. The value is there, and also not there, depending on who is asking. This whole lesson is about that split.
The black boxes below are a practice terminal: a safe sandbox that checks only the one command each step teaches, so you cannot break anything. The variables YOU create print the exact values shown. A few built-in variables (like your home folder path) hold values that belong to the machine, so those are shown as an example and marked "yours will differ."
A variable is a named box that holds a piece of text in your shell. You put a value in the box and give the box a name. Later you pull the value back out by that name. That is the whole idea: a name, and the text it stands for.
You create one with a single line: a name, an equals sign, and a value, with no spaces touching the equals sign. name=alice means "store the text alice in a box called name." To read the box back, you put a dollar sign in front of the name: $name. The dollar sign is the shell's cue that says "do not treat this as the literal word name, look up the box and drop its value in here instead."
Set one now. The shell prints nothing when a variable is set, so a blank prompt back means it worked:
name=alice
prompt: student@linuxcamp:~$ answer: name=alice output: hint: A name, an equals sign, then the value, with no spaces anywhere: name=alice
No output, and that is correct. Setting a variable is a quiet act; the shell just tucks the value away. The silence is the receipt. Next you read it back out.
A variable you cannot read is useless. The echo command prints whatever you hand it, and when you hand it $name, the shell swaps $name for the stored value FIRST, then echo prints the result. So echo $name prints the contents of the box, not the word name.
Read your variable back:
echo $name
prompt: student@linuxcamp:~$ answer: echo $name output: alice hint: The echo command, a space, then a dollar sign stuck to the name: echo $name
The shell saw $name, looked in the box, found alice, and replaced $name with it before echo ever ran. This swap is called expansion: the shell expands $name into its value. Every time you write a dollar sign in front of a name, expansion is what happens.
There is a safer way to write the same thing: ${name}, with curly braces around the name. It means exactly what $name means, but the braces draw a hard border around the name so the shell knows where it ends.
This matters the moment you glue a variable next to other letters. Say you want to print alices. Write $names and the shell hunts for a box called names, which does not exist, so you get nothing. Write ${name}s and the shell reads the box name, then prints a literal s right after. The braces say "the name stops here."
Print the value with braces to prove they do the same job:
echo ${name}
prompt: student@linuxcamp:~$ answer: echo ${name} output: alice hint: Same echo, but wrap the name in curly braces after the dollar sign: echo ${name}
Get in the habit of ${name} from day one. It never behaves worse than $name, and it saves you from the confusing empty output when a variable sits next to other text like ${name}s or ${dir}/file.
Here is the catch from the cold open. Your name variable lives in THIS shell only. It is a shell variable: private to the shell you are typing in. When you launch another program from that shell, the program is a child, and children do not inherit plain shell variables. The value simply is not passed down.
You can watch this happen. bash -c "..." starts a brand new child shell and runs the command inside the quotes. Ask that child to print name. Before you run it, decide what you expect: will the child see alice, or will it come back blank?
bash -c 'echo $name'
prompt: student@linuxcamp:~$ answer: bash -c 'echo $name' output: hint: Run bash with -c and a quoted command that echoes the name: bash -c 'echo $name'
Blank. The child shell printed an empty line because, to IT, name was never set. Your variable stayed behind in the parent shell where you created it. This is not a bug; it is the default rule. A plain shell variable is local, and it stops at the edge of the shell that owns it.
To let child programs see a variable, you export it. The export command marks a variable as inheritable, promoting it from a plain shell variable into an environment variable. An environment variable is a shell variable that has been exported, and that one word is the whole difference between the two kinds.
Export your variable, then ask a child shell the exact same question as before. This time, decide what you expect: now that it is exported, will the child see alice?
export name
prompt: student@linuxcamp:~$ answer: export name output: hint: The word export, a space, then the bare name with no dollar sign: export name
No output again, same quiet receipt as setting it. But something changed underneath: name is now flagged as inheritable. The next child program you launch will find it waiting. Prove it in the next step.
Run the very same child-shell test from two steps ago. Nothing about the command changes; only the export in between changed the outcome. That contrast is the entire lesson: same command, different result, because the variable crossed the border.
bash -c 'echo $name'
prompt: student@linuxcamp:~$ answer: bash -c 'echo $name' output: alice hint: The exact same child command as before: bash -c 'echo $name'
This time the child printed alice. Same command, opposite result. Before export, the box was private and the child saw nothing. After export, the box is part of the environment that every child inherits, so the child read it plainly. Plain shell variable, then environment variable: the border between them is a single export.
You do not start from empty. The shell sets a handful of environment variables for you the moment you log in, and you read them the same way you read your own: with a dollar sign. These are the ones you will meet constantly:
Read one now. echo $HOME prints the path to your home folder:
echo $HOME
prompt: student@linuxcamp:~$ answer: echo $HOME output: /home/student hint: The echo command, a space, then a dollar sign and the name in capitals: echo $HOME
That /home/student is this machine's home path, shown as an example. On YOUR machine $HOME reads whatever your own home folder is, and $USER, $PWD, and $PATH hold your own live values too. What never changes is the MOVE: a dollar sign in front of the name reads the box. By convention these built-in environment variables are written in UPPERCASE, which is why you see HOME and not home.
One mistake catches almost everyone on their first day, so meet it on purpose now. When you set a variable, the equals sign must have no spaces around it. Put a space in and the shell reads your line completely differently.
Watch what name = alice does, with spaces around the equals sign:
name = alice
prompt: student@linuxcamp:~$ answer: name = alice output: name: command not found hint: Type it with spaces on purpose to see the error the shell gives back: name = alice
name: command not found. With spaces, the shell stops seeing an assignment. It reads the first word, name, as a command to run, and = and alice as arguments to hand it. There is no program called name, so the shell reports it cannot find one. The fix is to close the gaps: name=alice, no spaces. Remember this error text, because you WILL type a stray space one day, and now you will know exactly what it means.
A related non-error worth knowing: if you read a variable that was never set, like echo $missing, the shell does not complain. It expands the unset name to an empty string and prints a blank line. Silence, not an error. That is why a typo in a variable name shows up as mysteriously missing output rather than a warning, and it is another reason to reach for ${name} so the name is unmistakable.
Scaffolding off. No commands are printed this time. You have every piece you need.
Create a variable called city holding the text paris, then mark it so that any program you launch from this shell will inherit it. Two lines. Think about which command stores the value, and which command promotes it from a private shell variable to an environment variable a child can see.
prompt: student@linuxcamp:~$ answer: city=paris output: hint: First store the value with name equals value and no spaces. Think city, an equals sign, then paris.
prompt: student@linuxcamp:~$ answer: export city output: hint: One word promotes a shell variable to an environment variable, followed by the bare name. Think export, then the name.
That is the everyday pattern. city=paris put the text in the box with no spaces around the equals. export city marked the box inheritable, so it is now an environment variable and every child program you launch will find city set to paris. Set, then export: that two-step move is exactly what a working engineer types when a program needs a value passed down to it. You recalled both commands from memory, which is the same recall the real machine will ask of you.
You earned this cheat sheet. Every row is something you just ran:
And the one idea to keep: a shell variable is private to the shell you are in; an environment variable is a shell variable you exported, so child programs inherit it. Set with no spaces, read with $, share with export.
You can do both jobs in one line: export name=alice sets and exports at the same time. It is the same as name=alice followed by export name, just shorter. Once the set-then-export idea is solid, this shortcut is what you will reach for.
The practice terminal has shown you the split at the heart of the shell. You can create a variable with no spaces, read it back with $ and ${}, watch a child program come back blank, and cross that border with export. You typed every one of those yourself.
The Bash Environment module ends with one real Linux machine, the Bash Environment capstone mission, and that is where you put these to work for real. A VM boots just for you, with its own live environment full of real variables. It hands you objectives that use exactly what you practiced across this module: setting variables, exporting them, and reading the environment. One difference from here: the mission shows no commands. You read the objective, you recall the command, you type it. That recall is what makes it stick.
Finish the other Bash Environment lessons, then go shape a real environment for yourself.
Practice Shell Variables vs Environment Variables in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.