Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

What is the difference between the command

$ env FOO=bar baz

and

$ FOO=bar baz

What effect does env have?

share|improve this question
4  
Sort of a side question, but what is it the feature itself called when you set an environment variable for a single subcommand like that? I've always had a hard time finding info on this because I don't know what it's called. –  John Cromartie May 15 at 18:36
1  
@JohnCromartie, you should ask that as a question. –  cjm May 15 at 19:04
1  
For bash, it's documented here: gnu.org/software/bash/manual/… –  glenn jackman May 15 at 19:24
2  
@JohnCromartie It's an optional component of every shell command, so it is in the "Simple Commands" section of most shell manuals. For POSIX, that would be here. glenn linked the analogous section from the bash manual for you already. –  jw013 May 16 at 1:41
    
Setting a variable that does not exist via an assignment creates a shell variable. Setting it via ENV or exporting the variable pushes the variable into the shell's execution environment. Changing the value of an existing variable will update the execution environment value if one exists, otherwise change it in the shell internal variables. –  Johan May 21 at 11:01
add comment

5 Answers 5

up vote 24 down vote accepted

They are functionally equivalent.

The main difference is that env FOO=bar baz involves invoking an intermediary process between the shell and baz, where as with FOO=bar baz the shell directly invokes baz.
So in that regard, FOO=bar baz is preferred.

The only situations I find myself using env FOO=bar in is where I have to pass a command to another command.
As a specific example, lets say I have a wrapper script that performs some modifications of the environment, and then calls exec on the command that was passed to it, such as:

#!/bin/bash
FOO=bob
some stuff
exec "$@"

If you execute it as myscript FOO=bar baz, the exec will throw an error as exec FOO=bar baz is invalid.
Instead you call it as myscript env FOO=bar baz which gets executed as exec env FOO=bar baz, and is perfectly valid.

share|improve this answer
1  
You can do FOO=bar exec baz though, so you don't need env in your last point. –  Stéphane Chazelas May 15 at 19:25
    
When you exec something, does it use your current environment? –  glenn jackman May 15 at 19:25
1  
Ditto @StephaneChazelas, and you can also sudo FOO=bar baz to pass environment variables without the need for env. –  mtmiller May 15 at 19:27
1  
@StephaneChazelas that only works if I want to put FOO=bar in the script. If FOO isn't always bar, I don't want to hard code it, and instead pass it in. –  Patrick May 15 at 19:27
    
@glennjackman yes it does, as long as the variables are exported or passed before the exec, such as FOO=bar exec baz. –  Patrick May 15 at 19:28
show 3 more comments

In this particular example, there is no effective difference, assuming your shell is a POSIX-compatible shell, and assuming baz is an executable and not a shell builtin.

If your shell is not a POSIX-compatible shell, for example csh or tcsh, the syntax

FOO=bar baz

does not work, and there is no equivalent shell syntax. For those shells, the env command is the only way to override or inject environment variables for a single command.

If baz is a shell builtin, let's say fc for example, then env will not give the same results, because env is executing a new process instead of being run directly by the command shell. Moreover, there is no fc executable, it can only be run as a shell builtin because of the way it interacts with the shell environment, and so env will never work with a builtin like fc.

In addition, env offers the -i option, which allows you to start a command in an empty environment with only a specified set of environment variables. So env can be very useful for starting processes in sanitized environments, for example

env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz
share|improve this answer
    
When I used to use tcsh I would write (setenv FOO bar; baz) to get the equivalent function. –  Barmar May 21 at 19:53
add comment

In addition to what has already been said

VAR=value cmd args > redirs

being a shell (Bourne/POSIX) feature, you're limited in the name of the environment variables you pass to cmd. They have to be valid shell variable names and must not be read-only or special variables to the shell.

For instance, you cannot do:

1=foo cmd

Or

+++=bar cmd

bash doesn't allow you to do:

SHELLOPTS=xtrace cmd

While you can do:

env 1=foo cmd
env +++=bar cmd
env '=baz' cmd

(not that you want or should want to do that). Or:

env SHELLOPTS=xtrace cmd

(I sometimes need to do that).

Note that with env you still cannot pass an environment variable string that doesn't contain a = (not that you would want to do that either).

share|improve this answer
add comment

One use of env is to allow $PATH searching of executables in shebang lines (because env considers the $PATH when searching for the executable). This is useful if the executable you want to invoke may be in different places on different machines. For example,

#!/usr/bin/env perl

in the first line of a script with executable bit set will execute this script with Perl no matter whether it is installed in /usr/bin/perl or in /usr/local/bin/perl or in a completely different place, as long as the directory is in the path.

Of course that path search comes with an added risk, but then, the risk is not larger than if you had explicitly written perl yourscript.pl, which also looks up perl in the search path.

share|improve this answer
add comment

Another time when env is really useful is if you want to control the environment completely. I run a server program (Informix, in case you can't guess) whose environment I want to control completely. I run it using env at the end of a script which sets a bunch of variables to the correct values:

env -i HOME="$IXD" \
       INFORMIXDIR="$IXD" \
       INFORMIXSERVER="$IXS" \
       ${IXC:+INFORMIXCONCSMCFG="$IXC"} \
       ${IXH:+INFORMIXSQLHOSTS="$IXH"} \
       IFX_LISTEN_TIMEOUT=3 \
       ONCONFIG="onconfig.$IXS" \
       PATH="/bin:/usr/bin:$IXD/bin" \
       SHELL=/bin/ksh \
       TZ=UTC0 \
    $ONINIT "$@"

The -i option zaps the existing environment. The subsequent VAR=value options set the environment variables that I want set; the name of the program is in $ONINIT, and any command line arguments are passed through verbatim with "$@".

The ${IXH:+INFORMIXSQLHOSTS="$IXH"} construct only passes INFORMIXSQLHOSTS="$IXH" to env if $IXH is set to a non-empty value.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.