LearnLinux FoundationsBash Shell Environment

env

env - a hands-on Linux lab on a real virtual machine.

Meet the invisible list every program inherits, and the one command that both shows it and edits it. Print the whole environment with bare env, run a command with an added variable using env NAME=value command, start from nothing with env -i, and drop one variable with env -u. Bare env output varies per machine, so the drills anchor on the byte-stable results you build yourself.

Every command you run starts life holding an invisible list. Type ls, and before it prints a single filename it already knows where your home folder is, what your username is, and which folders to search for programs. Nobody typed that in. It was handed over the moment the command started.

That list is called the environment, and it is passed silently from your shell to every program it launches. This lesson is about the one command that lets you SEE that list, and, better still, hand a program a changed copy of it. The command is env.

The black boxes in this lesson are a practice terminal: a safe sandbox that checks the one command each step teaches, so nothing you type can break anything. Some of what env prints is your machine's live environment, which changes from machine to machine, so those outputs are shown as one real example and marked. The outputs that matter for the drills are the ones you build yourself, and those are the same everywhere.

env has two jobs, and they sound unrelated until you see them side by side.

First, run with nothing after it, env prints the whole environment: every variable your shell is passing down, one per line, as NAME=value. Second, and this is the part people miss, env can run a program with a changed environment. You list some NAME=value pairs, then a command, and env starts that command with those variables added, just for that one run.

So env is both a window and a launcher. It shows you the list, and it hands the next program a version of the list you edited on the spot.

The idea goes back to how Unix has always started programs: a process receives its environment from whatever launched it, and passes its own copy down to whatever IT launches. env sits in the middle of that handoff. Its original job was simply to be a reliable launcher with a clean, predictable environment. That is why to this day the first line of many scripts reads #!/usr/bin/env bash: it asks env to find and start the right program.

Start with the window. Run env on its own and it prints every variable in your environment, one NAME=value per line. Before you run it, decide what you expect to see: your home folder? Your username? The list of folders where programs live?

env

prompt: student@linuxcamp:~$ answer: env output: SHELL=/bin/bash PWD=/home/student HOME=/home/student USER=student PATH=/usr/local/bin:/usr/bin:/bin hint: Just the three letters and Enter, nothing after them: env

There it is: the invisible list, made visible. HOME=/home/student is where your home folder lives, USER=student is who the system thinks you are, and PATH=/usr/local/bin:/usr/bin:/bin is the list of folders the shell searches when you type a command name. Each line is one variable a program inherits for free.

That exact list is this machine's, captured at one moment. On YOUR machine the values will differ (a different HOME, a different PATH), and a real environment usually has many more lines than the five shown here (LANG, TERM, SSH_CONNECTION, and more). What stays the same everywhere is the SHAPE: one NAME=value per line. That shape is the lesson, not the specific values.

Now the launcher. This is where env earns its place. You write env, then a NAME=value pair, then a command. env starts that command with the variable added to its environment, for that one run only, and then it is gone.

Watch this carefully. We add a variable called GREETING, set it to hi, and run a tiny program (bash -c runs the quoted line as a small script) that prints it back. Before you run it, commit to an answer: what single word lands on the screen?

env GREETING=hi bash -c 'echo $GREETING'

prompt: student@linuxcamp:~$ answer: env GREETING=hi bash -c 'echo $GREETING' output: hi hint: Type env, then GREETING=hi, then the little program: env GREETING=hi bash -c 'echo $GREETING'

One word: hi. Here is what happened. env took your current environment, added GREETING=hi to its copy, and started bash with that copy. Inside, echo $GREETING looked up the variable and found hi, because env had just planted it. The single quotes matter: they stop your OWN shell from touching $GREETING, so the lookup happens inside the new program, where the value actually lives. The instant that program finished, the GREETING variable vanished. Run env again and it is nowhere: you changed the environment for one command and nothing else.

Stop and notice what you just did. You did not export anything. You did not edit a config file. You handed one program a private, one-shot copy of the environment with an extra setting, and left your own shell untouched. That single trick, env NAME=value command, is how engineers test a program under a different setting without changing anything permanently. It is one of the most quietly useful patterns in the whole shell, and it is now yours.

Sometimes you want the opposite of adding a variable. You want a program to start with a completely blank list, inheriting nothing. The -i flag does exactly that: i for ignore the inherited environment. The program starts with an empty environment, so variables it would normally receive for free are simply not there.

Prove it. Normally $HOME is always set. Start bash with an empty environment and ask for $HOME anyway. Before you run it, decide: does a value print, or a blank line?

env -i bash -c 'echo $HOME'

prompt: student@linuxcamp:~$ answer: env -i bash -c 'echo $HOME' output:

hint: Add the -i flag right after env, then the same little program: env -i bash -c 'echo $HOME'

A blank line. echo printed nothing but an empty line because $HOME had no value to look up. env -i wiped the inherited list clean before starting bash, so HOME, PATH, USER, all of it, was gone. This is how you test a program in a sterile environment, to prove it does not secretly depend on some variable being set. The opposite of adding one variable is removing all of them.

There is a trap here worth walking through, because it confuses almost everyone the first time. env does not show EVERY variable you have set. It shows only the ones marked for export, the ones actually passed down to child programs. A plain shell variable, set but not exported, is invisible to env.

You can see the split without leaving the sandbox. A variable set the plain way lives only in your shell; env never sees it. That is not a bug, it is the whole distinction: env reports the environment that programs inherit, not the private scratch variables your shell keeps to itself. When you learn export in a later lesson, this is the line it moves a variable across.

A close cousin of env is printenv, coming in a later lesson. printenv also prints the environment, but that is ALL it does. env is the more powerful of the two because it can also run a command with a changed environment. If you only want to read, either works. If you want to launch a program with an edited environment, only env does that.

Scaffolding off. No command is printed this time. You have every piece you need.

You want to run a small program and hand it a single variable named COLOR with the value red, added just for that one run, then have the program print that value back. Use bash -c 'echo $COLOR' as the program. Build the line that adds the variable and runs it.

prompt: student@linuxcamp:~$ answer: env COLOR=red bash -c 'echo $COLOR' output: red hint: Same pattern as GREETING. Think env, then COLOR=red, then bash -c 'echo $COLOR'.

The word red. You reached for the exact pattern from earlier, env NAME=value command, and swapped in your own variable. env added COLOR=red to a copy of the environment, started bash with it, and echo $COLOR found the value and printed it. The instant the program finished, COLOR was gone. You built that line from memory, which is the same recall the real machine will ask of you.

Two things go wrong often enough to name.

The first: you put a command after the assignments that does not exist. env will say so plainly.

env GREETING=hi notacommand

prints:

env: 'notacommand': No such file or directory

That means env set your variable fine, but could not find a program by that name to run. Check the spelling of the command, and check it is really installed. The variable was never the problem.

The second is quieter: you set a variable the plain way and wonder why env does not show it.

COLOR=blue

then env prints its list and COLOR is nowhere in it. Nothing is broken. env shows only EXPORTED variables, and a plain assignment does not export. The value lives in your shell, just not in the environment programs inherit. That is the export line from the tip above, seen from the other side.

You earned this cheat sheet. Every row is a form of env you just ran or met:

The two faces to remember: bare env is a window onto the list every program inherits, and env NAME=value command is a launcher that hands one program an edited copy. And the trap: env shows only exported variables, never your shell's private ones.

The -u form is the surgical cousin of -i. Where -i wipes the whole environment, env -u NAME command removes just one variable, u for unset, and leaves everything else in place. Reach for it when a single variable is causing trouble and you want to run a program as if it had never been set.

The practice terminal has shown you both faces of env: the window that prints the environment, and the launcher that runs a command with a changed one. You added a variable for a single run, wiped the environment down to nothing, and learned why a plain variable stays hidden. Every one of those you typed yourself.

The Bash Environment module ends with one real Linux machine, the Bash Environment capstone mission, and that is where you use env for real. A VM boots just for you, with its own live environment full of variables you can read and change. It hands you objectives that use exactly what you practiced across this module: variables, export, PATH, and reading the environment that ties them together. 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 read and reshape a real environment for yourself.

Practice env in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.