Next: , Previous: , Up: Modified command invocation   [Contents][Index]


23.2 env: Run a command in a modified environment

env runs a command with a modified environment. Synopses:

env [option]… [name=value]… [command [args]…]
env -[v]S'[option]… [name=value]… [command [args]…]'
env

env is commonly used on first line of scripts (shebang line):

#!/usr/bin/env command
#!/usr/bin/env -[v]S[option]… [name=value]… command [args]…

Operands of the form ‘variable=value’ set the environment variable variable to value value. value may be empty (‘variable=’). Setting a variable to an empty value is different from unsetting it. These operands are evaluated left-to-right, so if two operands mention the same variable the earlier is ignored.

Environment variable names can be empty, and can contain any characters other than ‘=’ and ASCII NUL. However, it is wise to limit yourself to names that consist solely of underscores, digits, and ASCII letters, and that begin with a non-digit, as applications like the shell do not work well with other names.

The first operand that does not contain the character ‘=’ specifies the program to invoke; it is searched for according to the PATH environment variable. Any remaining arguments are passed as arguments to that program. The program should not be a special built-in utility (see Special built-in utilities).

Modifications to PATH take effect prior to searching for command. Use caution when reducing PATH; behavior is not portable when PATH is undefined or omits key directories such as /bin.

In the rare case that a utility contains a ‘=’ in the name, the only way to disambiguate it from a variable assignment is to use an intermediate command for command, and pass the problematic program name via args. For example, if ./prog= is an executable in the current PATH:

env prog= true # runs 'true', with prog= in environment
env ./prog= true # runs 'true', with ./prog= in environment
env -- prog= true # runs 'true', with prog= in environment
env sh -c '\prog= true' # runs 'prog=' with argument 'true'
env sh -c 'exec "$@"' sh prog= true # also runs 'prog='

If no command name is specified following the environment specifications, the resulting environment is printed. This is like specifying the printenv program.

For some examples, suppose the environment passed to env contains ‘LOGNAME=rms’, ‘EDITOR=emacs’, and ‘PATH=.:/gnubin:/hacks’:

23.2.1 General options

The program accepts the following options. Also see Common options. Options must precede operands.

-0
--null

Output a zero byte (ASCII NUL) at the end of each line, rather than a newline. This option enables other programs to parse the output even when that output would contain data with embedded newlines.

-u name
--unset=name

Remove variable name from the environment, if it was in the environment.

-
-i
--ignore-environment

Start with an empty environment, ignoring the inherited environment.

-C dir
--chdir=dir

Change the working directory to dir before invoking command. This differs from the shell built-in cd in that it starts command as a subprocess rather than altering the shell’s own working directory; this allows it to be chained with other commands that run commands in a different context. For example:

# Run 'true' with /chroot as its root directory and /srv as its working
# directory.
chroot /chroot env --chdir=/srv true
# Run 'true' with /build as its working directory, FOO=bar in its
# environment, and a time limit of five seconds.
env --chdir=/build FOO=bar timeout 5 true
-v
--debug

Show verbose information for each processing step.

$ env -v -uTERM A=B uname -s
unset:    TERM
setenv:   A=B
executing: uname
   arg[0]= 'uname'
   arg[1]= '-s'
Linux

When combined with -S it is recommended to list -v first, e.g. env -vS'string'.

-S string
--split-string=string

process and split string into separate arguments used to pass multiple arguments on shebang lines. env supports FreeBSD’s syntax of several escape sequences and environment variable expansions. See below for details and examples.

Exit status:

0   if no command is specified and the environment is output
125 if env itself fails
126 if command is found but cannot be invoked
127 if command cannot be found
the exit status of command otherwise

23.2.2 -S/--split-string usage in scripts

The -S/--split-string options enable using multiple arguments on the first one of scripts (shebang line, ‘#!’).

When a script’s interpreter is in a known location, scripts typically contain the absolute file name in their first line:

Shell script:
#!/bin/sh
echo hello
Perl script:
#!/usr/bin/perl
print "hello\n";
Python script:
#!/usr/bin/python3
print("hello")

When a script’s interpreter is in a non-standard location in the PATH environment variable, it is recommended to use env on the first line of the script to find the executable and run it:

Shell script:
#!/usr/bin/env bash
echo hello
Perl script:
#!/usr/bin/env perl
print "hello\n";
Python script:
#!/usr/bin/env python3
print("hello")

Most operating systems (e.g. GNU/Linux, BSDs) treat all text after the first space as a single argument. When using env in a script it is thus not possible to specify multiple arguments.

In the following example:

#!/usr/bin/env perl -T -w
print "hello\n";

The operating system treats ‘perl -T -w’ as one argument (the program’s name), and executing the script fails with:

/usr/bin/env: 'perl -T -w': No such file or directory

The -S option instructs env to split the single string into multiple arguments. The following example works as expected:

$ cat hello.pl
#!/usr/bin/env -S perl -T -w
print "hello\n";

$ chmod a+x hello.pl
$ ./hello.pl
hello

And is equivalent to running perl -T -w hello.pl on the command line prompt.

Testing and troubleshooting

To test env -S on the command line, use single quotes for the -S string to emulate a single paramter. Single quotes are not needed when using env -S in a shebang line on the first line of a script (the operating system already treats it as one argument).

The following command is equivalent to the hello.pl script above:

$ env -S'perl -T -w' hello.pl

To troubleshoot -S usage add the -v as the first argument (before -S).

Using -vS on a shebang line in a script:

$ cat hello-debug.pl
#!/usr/bin/env -vS perl -T -w
print "hello\n";

$ chmod a+x hello-debug.pl
$ ./hello-debug.pl
split -S:  'perl -T -w'
 into:    'perl'
     &    '-T'
     &    '-w'
executing: perl
   arg[0]= 'perl'
   arg[1]= '-T'
   arg[2]= '-w'
   arg[3]= './hello-debug.pl'
hello

Using -vS on the command line prompt (adding single quotes):

$ env -vS'perl -T -w' hello-debug.pl
split -S:  'perl -T -w'
 into:    'perl'
     &    '-T'
     &    '-w'
executing: perl
   arg[0]= 'perl'
   arg[1]= '-T'
   arg[2]= '-w'
   arg[3]= 'hello-debug.pl'
hello

23.2.3 -S/--split-string syntax

Splitting arguments by whitespace

Running env -Sstring splits the string into arguments based on unquoted spaces or tab characters.

In the following contrived example the awk variable ‘OFS’ will be <space>xyz<space> as these spaces are inside double quotes. The other space characters are used as argument separators:

$ cat one.awk
#!/usr/bin/env -S awk -v OFS=" xyz " -f
BEGIN {print 1,2,3}

$ chmod a+x one.awk
$ ./one.awk
1 xyz 2 xyz 3

When using -S on the command line prompt, remember to add single quotes around the entire string:

$ env -S'awk -v OFS=" xyz " -f' one.awk
1 xyz 2 xyz 3

Escape sequences

env supports several escape sequences. These sequences are processed when unquoted or inside double quotes (unless otherwise noted). Single quotes disable escape sequences except ‘\'’ and ‘\\’.

\cIgnore the remaining characters in the string. Cannot be used inside double quotes.
\fform-feed character (ASCII 0x0C)
\nnew-line character (ASCII 0x0A)
\rcarriage-return character (ASCII 0x0D)
\ttab character (ASCII 0x09)
\vvertical tab character (ASCII 0x0B)
\#A hash ‘#’ character. Used when a ‘#’ character is needed as the first character of an argument (see ’comments’ section below).
\$A dollar-sign character ‘$’. Unescaped ‘$’ characters are used to expand environment variables (see ’variables’ section below).
\_Inside double-quotes, replaced with a single space character. Outside quotes, treated as an argument separator. ‘\_’ can be used to avoid space characters in a shebang line (see examples below).
\"A double-quote character.
\'A single-quote character. This escape sequence works inside single-quoted strings.
\\A backslash character. This escape sequence works inside single-quoted strings.

The following awk script will use tab character as input and output field seperator (instead of spaces and tabs):

$ cat tabs.awk
#!/usr/bin/env -S awk -v FS="\t" -v OFS="\t" -f
...

Comments

The escape sequence ‘\c’ (used outside single/double quotes) causes env to ignore the rest of the string.

The ‘#’ character causes env to ignore the rest of the string when it appears as the first character of an argument. Use ‘\#’ to reverse this behavior.

$ env -S'printf %s\n A B C'
A
B
C

$ env -S'printf %s\n A# B C'
A#
B
C

$ env -S'printf %s\n A #B C'
A

$ env -S'printf %s\n A \#B C'
A
#B
C

$ env -S'printf %s\n A\cB C'
A

NOTE: The above examples use single quotes as they are executed on the command-line.

Environment variable expansion

The pattern ‘${VARNAME}’ is used to substitute a value from the environment variable. The pattern must include the curly braces (‘{’,‘}’). Without them env will reject the string. Special shell variables (such as ‘$@’, ‘$*’, ‘$$’) are not supported.

If the environment variable is empty or not set, the pattern will be replaced by an empty string. The value of ‘${VARNAME}’ will be that of the executed env, before any modifications using -i/--ignore-environment/-u/--unset or setting new values using ‘VAR=VALUE’.

The following python script prepends /opt/custom/modules to the python module search path environment variable (‘PYTHONPATH’):

$ cat custom.py
#!/usr/bin/env -S PYTHONPATH=/opt/custom/modules/:${PYTHONPATH} python
print "hello"
...

The expansion of ‘${PYTHONPATH}’ is performed by env, not by a shell. If the curly braces are omitted, env will fail:

$ cat custom.py
#!/usr/bin/env -S PYTHONPATH=/opt/custom/modules/:$PYTHONPATH python
print "hello"
...

$ chmod a+x custom.py
$ custom.py
/usr/bin/env: only ${VARNAME} expansion is supported, error at: $PYTHONPATH python

Environment variable expansion happens before clearing the environment (with -i) or unsetting specific variables (with -u):

$ env -S'-i OLDUSER=${USER} env'
OLDUSER=gordon

Use -v to diagnose the operations step-by-step:

$ env -vS'-i OLDUSER=${USER} env'
expanding ${USER} into 'gordon'
split -S:  '-i OLDUSER=${USER} env'
 into:    '-i'
     &    'OLDUSER=gordon'
     &    'env'
cleaning environ
setenv:   OLDUSER=gordon
executing: env
   arg[0]= 'env'
OLDUSER=gordon

Next: , Previous: , Up: Modified command invocation   [Contents][Index]