Managing Environment Variables with the env Command
Learn how Unix and Linux environment variables work and how to inspect, set, unset, and isolate them with the env command.
The env command lets you inspect the environment visible to a process and start a command with temporary, modified, or empty environment variables. It is useful for debugging, reproducible tests, scripts, locale control, and safer command execution.
What is a process environment?
An environment variable is a name-and-value setting associated with a process. Examples include PATH=/usr/bin:/bin and LANG=en_US.UTF-8. Programs read these values to decide where to find executables, which home directory to use, how to format text, and how to select application behavior.
When a process starts a child process, the child normally receives a copy of the parent's process environment. This is called inheritance. The child can change its own copy, but those changes do not modify the environment of its parent.
Shell variables and exported variables
A shell can hold ordinary shell variables that are known only to that shell. A variable becomes an environment variable for child processes when the shell exports it.
| Characteristic | Shell variable | Exported environment variable |
|---|---|---|
| Visible in the current shell | Yes | Yes |
| Passed to commands started by the shell | No | Yes |
| Typical assignment | NAME=value | export NAME=value |
| Removal from the shell | unset NAME | unset NAME |
NAME=local-value
export NAME
# NAME is now inherited by subsequently launched commands
Exporting a variable changes the current shell's future child environments. It still does not make the setting system-wide. Shell startup files, service managers, login configuration, and operating-system-specific settings are separate mechanisms.
What the env command does
With no command argument, env writes the environment entries it can see to standard output:
env
With a command, env prepares an environment and then invokes that command:
env NAME=value command
The launched program receives the altered environment. When that program exits, the shell's environment remains unchanged.
Common env options
| Option | Meaning | Typical use | Portability notes |
|---|---|---|---|
-i, --ignore-environment | Start with an empty environment before applying assignments | Clean tests and minimal execution contexts | -i is widely available; long-option support is commonly associated with GNU implementations |
-u NAME, --unset=NAME | Remove a variable from the environment passed to the command | Disable proxies or unwanted application settings | Option spelling and repeated-use behavior can vary; check the local manual |
-S STRING, --split-string STRING | Split a string into arguments | Pass multiple interpreter arguments in a shebang | Not part of the basic POSIX interface and not available on every system |
Viewing environment variables
Use env without arguments to list all inherited entries. Ordering is not guaranteed, so sorting can make output easier to compare:
env | sort
A pipe sends the standard output of one command to the standard input of another. For example, grep can select one entry:
env | grep '^PATH='
env | grep '^LANG='
env | grep '^LC_'
The caret in ^PATH= anchors the match to the beginning of the line, avoiding accidental matches in other values.
| Variable | Purpose | Example effect | Caution |
|---|---|---|---|
PATH | Colon-separated directories searched for commands | ls may be found in /usr/bin | An unsafe or empty value can select the wrong program or prevent lookup |
HOME | User's home directory | Applications find personal configuration files | A wrong value can make programs read or write the wrong files |
USER | Commonly identifies the account name | A program displays a user-specific greeting | It is input, not a security proof of identity |
SHELL | Commonly identifies the user's preferred shell | A tool chooses a default interactive shell | It may not describe the shell currently executing a script |
LANG | Default locale | Messages and formatting use a language and character set | Locale-dependent output can be unsuitable for parsers |
TERM | Terminal capability description | Full-screen programs select terminal control sequences | It can be absent in non-interactive processes |
PWD | Shell's recorded working directory | A prompt or program displays the current directory | Use a system call or pwd when authoritative filesystem state matters |
printenv is a related utility focused on displaying environment variables:
printenv
printenv PATH
Shell built-ins have different purposes. export displays or marks exported shell variables, while set commonly displays shell variables, functions, and shell state. Their exact output depends on the shell. env reports the environment passed to a process, not every internal shell variable.
Setting variables for one command
Put NAME=value arguments after env and before the command:
env DEBUG=1 my-program
DEBUG is available to my-program and any descendants it starts. It is not added to the calling shell after my-program exits.
Quoting values
Shell quoting controls argument boundaries before env receives them. Quote values containing spaces, wildcard characters, command-substitution syntax, or other characters meaningful to the shell:
env NAME='value with spaces' command
env MESSAGE="quoted value" command
env EMPTY= command
The last example supplies an existing variable with an empty value. An empty value is different from an unset variable: a program may distinguish NAME= from no NAME entry at all.
Quoting prevents the shell from splitting value with spaces into multiple arguments. It does not automatically escape data for every application; the receiving program still decides how to interpret the value.
Running with an empty or reduced environment
Use -i or --ignore-environment to discard inherited variables before applying new assignments:
env -i /usr/bin/env
env -i PATH=/usr/bin:/bin HOME="$HOME" command
The first command should display little or no environment, depending on the implementation. The second constructs a small environment containing an explicit PATH and the current value of HOME.
A clean environment is useful for:
- Finding hidden dependencies in build and test commands.
- Making automated output and behavior more reproducible.
- Debugging failures caused by shell startup files or inherited configuration.
- Reducing accidental propagation into sensitive or untrusted workloads.
Many programs need more than PATH and HOME. Add TERM for terminal-aware programs and a suitable LANG or locale variable when text behavior matters. Missing PATH means name-based command lookup may fail, so use an absolute executable path such as /usr/bin/program when appropriate.
Removing inherited variables
Use -u to remove one variable before launching a command. Repeat it to remove several:
env -u HTTP_PROXY -u HTTPS_PROXY command
env -u ALL_PROXY -u http_proxy -u https_proxy network-command
This is useful when a command should bypass inherited proxy settings. The same technique can remove locale variables, application configuration variables, or dynamic-loader-related variables that should not reach a child process.
Variable names are case-sensitive on many Unix-like systems. Proxy conventions often use both uppercase and lowercase names, so remove the forms that may be present. Inspect the environment before deciding which entries to remove.
Command lookup and PATH
When env is asked to run an executable name without a directory separator, the command is normally located using PATH. This is called command lookup:
env PATH=/usr/bin:/bin command
The assignment applies only to this invocation. A command with an absolute path names its executable directly:
env -i /usr/bin/env
/usr/bin/env -i /usr/bin/program
A relative path contains a directory reference such as ./program or tools/program. It is resolved relative to the current working directory and does not use PATH in the same way as a bare executable name.
Scripts should use a minimal, trusted PATH, especially in privileged contexts. Avoid relying on the current directory or on directories writable by untrusted users. In a normal shell, command -v program can help show which executable would be selected, but it does not replace verification of permissions and provenance.
Using env in shebang lines
A shebang is the first line of an executable script beginning with #!. The conventional form below asks env to locate python3 through PATH:
#!/usr/bin/env python3
This can be portable when the interpreter is installed in different locations on different systems. It also means the selected interpreter depends on the execution environment's PATH. An unexpected or attacker-controlled PATH can select an unintended interpreter, so use a controlled environment or a known absolute interpreter path when predictability and security are more important than installation flexibility.
Shebang argument parsing is handled by the operating system and can differ across Unix-like systems. Some systems pass the text after the interpreter as one argument; others provide different splitting behavior. Multiple interpreter options therefore may not work consistently in a simple shebang.
Where supported, env -S splits a string into multiple arguments:
#!/usr/bin/env -S python3 -u
-S is an implementation extension rather than a universal POSIX feature. Check the local env manual and operating-system documentation before depending on it. A wrapper script is often the most portable solution when several interpreter arguments are required.
Locale and application behavior
Locale variables influence messages, sorting, character classification, encoding assumptions, and numeric or date formatting. For predictable command output, especially output consumed by a script, select a known locale:
env LC_ALL=C command
env LANG=C sort file.txt
LC_ALL overrides individual LC_* categories and LANG. If LC_ALL is set, it normally takes precedence over LANG. Use the narrowest override that meets the requirement; setting LC_ALL=C can change user-facing messages and character handling as well as sorting.
The same pattern works for application settings:
env DEBUG=1 APP_CONFIG=/tmp/test.conf application
env HTTP_PROXY= HTTPS_PROXY= ALL_PROXY= network-command
Whether an empty proxy variable disables a proxy depends on the application. Removing the variables with env -u is often clearer when the application treats empty and unset values differently.
Exit status and shell scripting
When env successfully starts a command, it generally returns that command's exit status. An exit status of zero conventionally means success; a nonzero value indicates failure. If env cannot find or execute the command, it reports an error and returns a failure status.
if env LC_ALL=C ./run-tests; then
echo "tests passed"
else
status=$?
echo "tests failed with status $status" >&2
exit "$status"
fi
For a temporary setting within a shell script, a direct assignment before a command is also common:
DEBUG=1 ./program
Use env when its explicit options, such as -i or -u, make the intended environment easier to see. Do not assume that running env NAME=value command will make NAME remain set in the script's shell.
Ways to run a command with altered settings
| Method | Scope | Persists after command? | Best use case |
|---|---|---|---|
env NAME=value command | That command and its descendants | No | Explicit one-time overrides |
NAME=value command | That command and its descendants | No | Short shell syntax for a temporary assignment |
export NAME=value | Current shell and later children | Yes, until unset or shell exit | A setting needed for several commands in a session |
env -i ... command | That command and its descendants | No | Minimal, reproducible execution |
unset NAME | Current shell and later children | Yes, until restored or shell exit | Removing a variable from an interactive session |
Portability and implementation differences
| Feature | POSIX baseline | GNU/Linux considerations | BSD/macOS considerations |
|---|---|---|---|
| Display environment | Supported without a command | Provided by GNU coreutils | Provided by the system utilities |
| Ignore inherited environment | Commonly available as -i | Long form --ignore-environment is commonly available | Check the local manual for long-option support |
| Unset variables | -u name is common | GNU syntax may also accept a long option | Syntax and repeated options can differ |
| Split shebang arguments | Not a universal baseline | -S may be available depending on GNU coreutils version | Availability varies by release and implementation |
Linux distributions, BSD systems, macOS, and other Unix-like systems may ship different env implementations. Consult the local manual page:
man env
env --help
Do not assume that GNU long options or -S work on every target system. Test scripts on the systems where they will run.
Security and operational guidance
- Do not trust an uncontrolled
PATHwhen selecting interpreters or executables. Use a known path or a carefully constructed trusted path for privileged work. - Environment variables can expose secrets to child processes, diagnostics, crash reports, logs, or process-inspection mechanisms, depending on the operating system and permissions. Prefer a dedicated secret-management mechanism for sensitive credentials.
- Use
env -ior multiple-uoptions to limit inherited values when running untrusted or sensitive workloads. - Check for accidental propagation of credentials, proxy variables, application tokens, and dynamic-loader-related variables.
- Remember that environment isolation is not a complete security boundary. The child still has the permissions of the account that launched it unless another isolation mechanism is used.
Troubleshooting
“Command not found” or an executable cannot be found
- The command may be absent from
PATH. env -imay have removedPATH.- The executable name may be misspelled or the program may not be installed.
Inspect the normal shell's lookup result with command -v program, inspect the value with env | grep '^PATH=' is invalid? No need. Use proper:
env | grep '^PATH='
command -v program
/usr/local/bin/program
A command fails only under env -i
The program may depend on PATH, HOME, locale settings, configuration variables, credentials, or another inherited value. Start with a minimal environment and add only required variables incrementally:
env -i PATH=/usr/bin:/bin HOME="$HOME" LANG=C command
A variable disappears after env finishes
This is expected: env changes the child environment, not the parent shell. Use NAME=value followed by export NAME when the setting must remain available to later commands in the current shell.
The wrong interpreter runs from a shebang
The first matching interpreter in PATH is being selected, or the script is being launched with a modified PATH. Inspect and control PATH, or replace the shebang with a known absolute interpreter path when that is appropriate.
Shebang arguments behave unexpectedly
The operating system's shebang parser may limit or combine arguments, and the installed env may not support -S. Check local documentation, use a simpler shebang, or call a wrapper script.
Sorting or messages differ
Inspect LANG and LC_* variables. For machine-oriented tests, try env LC_ALL=C command, while remembering that this also changes language and character behavior.
A sensitive setting reaches a child unexpectedly
The setting was probably exported and inherited. Construct a reduced environment with env -i, or remove selected values with env -u NAME.
Exam-relevant notes
envwithout a command lists the current process environment.env NAME=value commandchanges the environment for that command and its descendants only.env -istarts with no inherited environment; essential values such asPATHmay need to be restored.env -u NAME commandremoves an inherited variable for one command.- A shell variable is not inherited unless it is exported.
- A child receives a copy of its parent's environment; child changes do not flow back to the parent.
PATHcontrols lookup of bare executable names, while absolute paths identify executables directly.#!/usr/bin/env interpreterimproves interpreter-location portability but depends onPATH.-Sis useful for multiple shebang arguments where supported, but it is not universally portable.envnormally returns the executed program's exit status, but it returns failure if it cannot start that program.
For related material, see environment management with env.