Read

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.

VariableMeaning
HOMEYour home directory; cd alone goes there (here /root/, with a trailing slash)
PATHDirectories searched for commands, in order (lesson 70)
USER, SHELLWho you are and your login shell
PWDCurrent directory, kept up to date by the shell
TERMTerminal type, so programs know which escape codes work
EDITOR, PAGERPreferred editor and pager for programs that open one
PS1The prompt; \W% here prints the directory name and %
SHLVLHow 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

CommandWhat it does
NAME=valueCreate a shell variable (not inherited by children).
export NAME=valueSet and export: children get a copy.
unset NAMERemove a variable.
env / printenvPrint the whole environment.
printenv NAMEPrint one value; exit status 1 if unset.
setAll shell variables, exported or not.
NAME=value cmdSet a variable for one command only.
env -i cmd / env -u NAME cmdRun with an empty environment / without one variable.

Quiz

  1. After `X=1` (no export), what does `sh -c 'echo $X'` print?

    • 1
    • An empty line
    • An error
    • X
  2. Which command prints only the value of PATH?

    • env PATH
    • printenv PATH
    • set PATH
    • export PATH
  3. 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
  4. 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
  5. Which command also shows variables that were never exported?

    • env
    • printenv
    • set
    • export -p

Practice

  1. Use `printenv` to write the value of `HOME` (just the value) into `/root/lab/l69/home.txt`.

  2. Run `sh -c 'echo $GREETING'` with `GREETING` set to `hola` for that command only, saving its output into `/root/lab/l69/greet.txt`.

  3. 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.