Module 7 · The system, disks and the environment
Environment variables: env, export, printenv
The difference between a shell variable and an environment variable, how export passes values down to child processes, and how env and printenv show or change the environment of a single command.
What you will learn
- Tell shell variables from environment variables and use `export` and `unset`.
- Inspect the environment with `env`, `printenv`, `export -p` and `set`.
- Change the environment of one command with `VAR=value cmd`, `env -u` and `env -i`.
Every process carries a small list of NAME=value strings called its environment. It receives a copy from its parent when it starts, and hands a copy to every child it creates. Programs read it to learn things nobody passed them as arguments: where your home is (HOME), where to look for commands (PATH), which editor you prefer (EDITOR), what kind of terminal they are drawing on (TERM). In lesson 60 you saw it raw in /proc/PID/environ; this lesson is about controlling it from the shell.
Shell variables and exported variables
~% COLOR=blue
~% echo $COLOR
blue
~% sh -c 'echo "child sees [$COLOR]"'
child sees []
~% export COLOR
~% sh -c 'echo "child sees [$COLOR]"'
child sees [blue]
~% export EDITOR=vi
~% unset COLOR
NAME=value (no spaces around =) creates a shell variable: it lives only in this shell's memory, and no command you start can see it. export NAME marks it to be copied into the environment of every child, and export NAME=value sets and exports in one step. unset NAME removes it. The copy only flows downwards: a child can change its own environment as much as it likes, and the parent never notices. That is why a script that runs cd or export cannot change the shell that started it, unless you *source* it with . (lesson 70).
Looking at the environment
~% env
USER=root
SHLVL=2
HOME=/root/
OLDPWD=/
PAGER=/bin/more
PS1=\W%
TERM=linux
BOOT_IMAGE=/boot/bzImage
PATH=/bin:/sbin:/usr/bin:/usr/sbin
SHELL=/bin/sh
PWD=/root
EDITOR=/bin/vi
~% printenv HOME
/root/
~% printenv NOPE; echo $?
1
env and printenv with no arguments print the whole environment, one variable per line. printenv NAME prints just one value and exits with 1 if it is not set, a tidy test for scripts. export -p lists the exported variables in a form you could paste back into a shell. set shows more: every shell variable, exported or not, including the shell's own internals such as PS2, IFS or PPID. If a value appears in set but not in env, it was never exported.
| Variable | Meaning |
|---|---|
HOME | Your home directory; cd alone goes there (here /root/, with a trailing slash) |
PATH | Directories searched for commands, in order (lesson 70) |
USER, SHELL | Who you are and your login shell |
PWD | Current directory, kept up to date by the shell |
TERM | Terminal type, so programs know which escape codes work |
EDITOR, PAGER | Preferred editor and pager for programs that open one |
PS1 | The prompt; \W% here prints the directory name and % |
SHLVL | How many shells deep you are |
Changing the environment of one command
~% GREETING=hola sh -c 'echo $GREETING'
hola
~% echo "[$GREETING]"
[]
~% env GREETING=hi sh -c 'echo $GREETING'
hi
~% env -u HOME sh -c 'echo "[$HOME]"'
[]
~% env -i sh -c env
SHLVL=1
PWD=/root
Putting assignments before a command sets them in that command's environment only; your shell is untouched afterwards. It is the everyday way to run something with a different setting: TZ=UTC date, LANG=C sort. env NAME=value CMD does the same and also works from programs that are not shells. env -u NAME CMD runs CMD with one variable removed, and env -i CMD with an empty environment, which is how you reproduce the bare conditions of a cron job or a service when something *works in my terminal but not there*.
Commands in this lesson
| Command | What it does |
|---|---|
NAME=value | Create a shell variable (not inherited by children). |
export NAME=value | Set and export: children get a copy. |
unset NAME | Remove a variable. |
env / printenv | Print the whole environment. |
printenv NAME | Print one value; exit status 1 if unset. |
set | All shell variables, exported or not. |
NAME=value cmd | Set a variable for one command only. |
env -i cmd / env -u NAME cmd | Run with an empty environment / without one variable. |
Quiz
After `X=1` (no export), what does `sh -c 'echo $X'` print?
- 1
- An empty line
- An error
- X
Which command prints only the value of PATH?
- env PATH
- printenv PATH
- set PATH
- export PATH
What does `TZ=UTC date` do to your shell's TZ afterwards?
- Sets it to UTC permanently
- Nothing: the assignment applies to that one command
- Exports it
- Unsets it
A script runs `export DEBUG=1` and exits. Is DEBUG set in the shell that ran it?
- Yes, export makes it global
- No: the environment is copied down to children, never back up
- Only if the script is run as root
- Only until the next command
Which command also shows variables that were never exported?
- env
- printenv
- set
- export -p
Practice
Use `printenv` to write the value of `HOME` (just the value) into `/root/lab/l69/home.txt`.
Run `sh -c 'echo $GREETING'` with `GREETING` set to `hola` for that command only, saving its output into `/root/lab/l69/greet.txt`.
Export a variable `LAB` with the value `69`, then save the whole environment, as printed by `env`, into `/root/lab/l69/env.txt`.
Open this lesson in the app to do the tasks in a real Linux machine and have them checked.