env Command: Running Commands with a Modified Environment

env Command: Running Commands with a Modified Environment

What is the env command?

Conclusion: env is a coreutils tool that runs a command with a modified environment. Written as env VAR=value command, it lets you run one command in a different environment without polluting your current shell.

env has two main jobs:

  • Set environment variables temporarily and run a command (env LANG=C date changes a variable for that one invocation)
  • List the current environment when run with no arguments (same as printenv)

It is also widely used in a script's shebang line (#!/usr/bin/env python3) to locate an interpreter via PATH.

Environment for this article

  • GNU coreutils env (Ubuntu / Debian / RHEL-based and other common Linux distributions)
  • Some options (-C / -S) depend on the coreutils version. See below.

Why use env VAR=value?

Conclusion: Because you want a variable to apply to one command only, without making it permanent and without polluting the current shell. export persists; env is one-shot.

There are several ways to run a command with a changed variable. Know the differences.

# (1) Shell built-in temporary assignment (no env)
$ LANG=C date

# (2) Temporary assignment via env
$ env LANG=C date

# (3) export (affects every later command, persistent)
$ export LANG=C
$ date

Forms (1) and (2) both change the variable for that single invocation. Form (3), export, keeps the change for every command you run afterward. When you want "just this once" or "do not leave the setting behind," pick (1) or (2).

How (1) and (2) differ

  • LANG=C date is shell syntax (a prefix assignment). The shell interprets it.
  • env LANG=C date launches the separate env executable, which builds the environment in a child process and then execs date.

For interactive use the result is the same. env becomes necessary when no shell is involved: shebang lines, arguments to exec-family APIs, or starting from an empty environment.

Set a variable temporarily and run

Conclusion: Write env NAME=value command args.... List multiple variables separated by spaces.

# Show the date with the time zone temporarily set to UTC
$ env TZ=UTC date

# Force the C locale to get English messages (handy for log investigation)
$ env LANG=C ls /nonexistent
ls: cannot access '/nonexistent': No such file or directory

To set several variables at once, list them in sequence:

$ env LANG=C LC_ALL=C TZ=UTC ./myscript.sh

Isolating locale-related errors

In a non-English environment, error messages may be translated and hard to search for. Pinning messages to English with env LANG=C command makes searching and filing issues easier.

Run with an empty environment (env -i)

Conclusion: env -i starts the command with all inherited environment variables removed. It is ideal for isolating "works only on my machine" problems.

# Check what remains (almost nothing)
$ env -i env

With -i (--ignore-environment), even PATH is not inherited. So under -i you must specify the command by absolute path or pass the variables you need explicitly.

# PATH is gone, so pass only the variables you need
$ env -i PATH=/usr/bin:/bin LANG=C ./myscript.sh

Under env -i, variables such as HOME, PATH, and LANG are undefined. If a script depends on them, it may misbehave. Passing only the variables you actually need is the safe pattern.

Run without a specific variable (env -u)

Conclusion: env -u NAME removes only that variable before running the command. Unlike -i, which clears everything, use it to disable a single variable.

# Temporarily disable proxy settings and test the connection
$ env -u http_proxy -u https_proxy curl https://example.com

-u (--unset) can be repeated for each variable. It lets you test the hypothesis "maybe this variable is the culprit" without editing any config file.

Run in a different directory (env -C)

Conclusion: env -C DIR command changes to the given directory before running the command. It packs cd DIR && command into one line without a subshell.

$ env -C /var/log tail -n 20 syslog

-C (--chdir) is available in coreutils 8.28 and later. It is unavailable in older environments. Check with env --version (see below).

Using /usr/bin/env in a shebang

Conclusion: A shebang like #!/usr/bin/env python3 finds the interpreter through PATH. It avoids hardcoding an absolute interpreter path, making the script portable.

#!/usr/bin/env python3
print("hello")

Writing #!/usr/bin/python3 directly breaks on systems where Python lives elsewhere (/usr/local/bin, a virtualenv, and so on). #!/usr/bin/env python3 searches PATH, so it uses the first python3 found in that user's environment.

#!/usr/bin/env -S python3 -u

To pass arguments to the interpreter in a shebang line, use -S (--split-string). A shebang normally allows only one argument; -S splits the string into multiple arguments.

-S requires coreutils 8.30 or later. Support also differs on macOS (BSD env), so verify the target environment before using it in distributed scripts.

env vs printenv vs set

Conclusion: env with no arguments lists environment variables only. Use set for all variables including shell variables, and printenv NAME for a single one.

Goal Command
List environment variables env or printenv
Show one environment variable printenv PATH (env alone cannot filter)
Include shell variables too set (bash built-in)
Set temporarily and run env VAR=val cmd

Passing a single argument like env PATH does not print the value: env treats it as a command name and reports "No such file or directory." To see just the value, use printenv PATH or echo "$PATH".

Troubleshooting

Conclusion: The common stumbles with env are "no PATH after -i" and "-C / -S unavailable on an old system." A version check resolves most of them.

"env: '...': No such file or directory"

env treats the first argument without an = as a command name. You get this error from env LANG C date (a missing =) or env PATH (trying to read a value). Make sure the form is NAME=value.

Command not found after env -i

-i also clears PATH. Either specify PATH explicitly as in env -i PATH=/usr/bin:/bin command, or give the command by absolute path.

# Check the env version (to decide whether -C / -S are available)
$ env --version | head -1
env (GNU coreutils) 9.4

Next Reading