Do you understand the argument list?
For example, if you type ls -l foo bar
,
the shell executes /bin/ls
with an argument list consisting of four strings:
whereas, if you type ls -l "foo bar"
(or ls -l 'foo bar'
or ls -l foo\ bar
),
the shell executes /bin/ls
with an argument list consisting of three strings:
and ls -l *
might get you something like:
ls
-l
ant
bat
cat
dog
etc
…
i.e., whatever files are in the current directory.
Well,
the environment is basically just a second argument list.
Perhaps it would be better to say “the environment is a second list of strings,
structured exactly like the argument list, but treated differently.”
If you look at execve(2),
you’ll see that the execve
system call takes three arguments:
- char *filename, (the program to execute; e.g.,
/bin/ls
)
- char *argv[],
- char *envp[]
Whenever any program executes any other program, it is basically using execve
(possibly via some higher-level function, such as execl
),
so it is passing an argument list and an environment list.
The environment list looks a lot like the output from env
; e.g.,
HOME=/home/fred
USERNAME=fred
PATH=/bin:/usr/bin:…
TERM=xterm
SHELL=/bin/bash
PWD=/home/fred/Super_User_files
etc…
The executed program can do whatever it wants with the environment list —
look at it (e.g., with getenv
), modify it, or ignore it —
the same things it can do with the argument list.
When a program executes another program
with one of the higher-level execute functions, like execl
,
it automatically calls execve
with the same environment list that was passed in to the program.
And that’s what happens in 90% of the programs that execute other programs.
But shells let you modify the environment,
and then they use execve
directly
to pass the most up-to-date user-specified environment
to every program that it runs.
TL;DR
Every process contains its environment list in memory,
the same way it contains its argument list and ordinary variables.
The environment is passed from program to program through the exec
mechanism.
Library functions make it easy for a program to pass its own environment
to any other program that it runs.
(Naturally, environment is preserved (copied) across a fork
,
just as all other local memory is.)
The kernel doesn’t really know anything about the environment
except for the fact that it provides a means
for the environment to be passed through execve
.