Home / Alt manpages / env(1)

  • env(1)
  • User command
  • linux

Run Commands with a Controlled Environment Using env

You will finish with a repeatable way to run one command with selected environment variables, a different working directory or no inherited environment at all. The examples use GNU env from coreutils 9.4, installed here as package version 9.4-3ubuntu6.3.

Allow about ten minutes. You need a shell and the coreutils package, which is normally already installed. The examples only affect child processes. They do not change your shell, system configuration or service definitions, so no elevated privileges are needed.

1. Confirm the installed command

Check the binary and version before relying on an option in a script:

$ command -v env
/usr/bin/env
$ env --version | head -n 1
env (GNU coreutils) 9.4

This guide targets GNU env. Other Unix implementations can have a smaller option set, so do not copy the long options into a portable POSIX script without checking its target systems.

2. Set variables for one command

Put NAME=VALUE arguments after env options and before the command. The assignments are passed to the child, not applied to the current shell:

$ env APP_MODE=staging FEATURE_FLAG=1 /bin/sh -c \
  'printf "APP_MODE=%s FEATURE_FLAG=%s\n" "$APP_MODE" "$FEATURE_FLAG"'
APP_MODE=staging FEATURE_FLAG=1
$ printf 'APP_MODE=%s\n' "${APP_MODE-unset}"
APP_MODE=unset

The quotes matter. The inner shell expands the variables after env has started it. The final command is a checkpoint: your interactive shell still has no APP_MODE value. Use this pattern when a test, build or one-off administrative command needs a temporary setting.

3. Start with an empty environment

Use -i, also written --ignore-environment, when inherited variables could hide a dependency. Add back only the values the command needs:

$ env -i HOME=/tmp/demo PATH=/usr/bin:/bin /bin/sh -c \
  'printf "HOME=%s\nPATH=%s\n" "$HOME" "$PATH"; env | wc -l'
HOME=/tmp/demo
PATH=/usr/bin:/bin
2

An empty environment is stricter than a clean login shell. It can omit variables that programs normally expect, including locale and configuration paths. If a command fails after -i, add variables deliberately rather than copying your entire environment back without checking what introduced the dependency.

A lone - is another spelling for ignoring the inherited environment, but -i is easier to recognise during review.

4. Remove one inherited variable

Use -u NAME or --unset=NAME when most of the environment is useful but one value must not reach the child:

$ export DEMO_SECRET='do-not-pass-this-on'
$ env -u DEMO_SECRET /bin/sh -c \
  'printf "DEMO_SECRET=%s\n" "${DEMO_SECRET-unset}"'
DEMO_SECRET=unset
$ unset DEMO_SECRET

The last unset restores this shell to the state it had before the demonstration. Treat environment variables as potentially sensitive: they can be visible to the child and, depending on the program, may be recorded in diagnostics or logs. Do not use env as a promise that a secret is erased from every process or shell history.

5. Run from a specific directory

GNU env 9.4 supports -C DIR, or --chdir=DIR, to change the child process's working directory:

$ env -C /tmp /bin/pwd
/tmp
$ pwd
/home/andy/src/manpages/prompts/generated/env-1

The directory must exist and be accessible before the command starts. This is useful when a tool has no own working-directory option, but it does not create the directory and it does not change the caller's directory. Check the path before using it in automation:

$ test -d /path/to/workdir && env -C /path/to/workdir /path/to/program

6. Understand command boundaries and exit statuses

Everything after the environment assignments belongs to the command. If the command is a shell, quote its script so the child, rather than the parent, expands the variables:

$ env RUN_NUMBER=42 /bin/sh -c 'printf "run=%s\n" "$RUN_NUMBER"'
run=42

When the child starts, env normally returns the child's status unchanged:

$ env /bin/sh -c 'exit 7'
$ printf 'status=%s\n' "$?"
status=7

The manual reserves status 125 for an env failure, 126 when a found command cannot be invoked, and 127 when the command cannot be found. These values help a script distinguish its own failure from the program it launched, although a child program can technically choose any exit status itself.

For example, this deliberately names a command that is not present:

$ env /path/that/does/not/exist
env: '/path/that/does/not/exist': No such file or directory
$ printf 'status=%s\n' "$?"
status=127

The wording can vary slightly by locale and coreutils build. The status is the useful part.

7. Use -S only for shebang argument splitting

The -S or --split-string option splits one string into separate arguments. Its main use is a script interpreter line that needs multiple interpreter arguments:

#!/usr/bin/env -S perl -w -T

Without -S, env would look for one executable whose name included the spaces. Do not use this option to turn untrusted text into a command line. Shell quoting, variable expansion and interpreter-specific parsing can make the result surprising; keep a shebang's arguments fixed and reviewable.

8. Avoid the common traps

Do not confuse env NAME=value command with NAME=value command. Both are temporary shell assignments in ordinary shells, but env is useful when you need its other features, when the command is selected dynamically, or when a shebang invokes it.

Do not put an option-looking value before the command boundary without checking it. Use the command's documented end-of-options convention where supported, and quote values containing spaces or shell metacharacters. Remember that env does not interpret shell syntax itself: pipelines, redirections and command substitutions require a shell such as /bin/sh -c.

Finally, changing the environment can change configuration, credentials, library search paths and proxy behaviour. Before using -i, -u or a replacement PATH in a service wrapper, test the exact command as the service account and keep the previous wrapper available for recovery.

Done means

  • You confirmed that the installed implementation is GNU coreutils env 9.4.
  • Temporary variables reached the child without changing the current shell.
  • You can choose between setting, removing and isolating environment variables.
  • You can run a child in a different directory while leaving your shell where it was.
  • You understand that env returns the child's status, with 125, 126 and 127 reserved for its own launch failures.
  • You have treated environment changes and shebang parsing as reviewable configuration, not invisible magic.