20

Let's say I invoke A=B command and env A=B command in bash. Is there any situation where there might be a difference between both invokations?

1 Answers1

27

They serve the same purpose (pass the given env vars to the command). However a few notable differences:

A=B command

is a shell (Bourne/POSIX/rc) construct.

For instance, you can do:

A=B find . -exec cmd '{}' +

or:

find . -exec env A=B cmd '{}' +

But you can't do:

find . -exec A=B cmd '{}' +

Because find is not invoking a shell to run that command.

On the other hand, env being an external command, you can't do:

f() { ...; }
env A=B f

or:

env A=B eval '...'

Also:

A=B cmd

works only with env vars that are valid shell variable names. You need env for any other env var name:

env 'my var=foo' cmd...

bash resets the _ variable:

bash-4.3$ _=xxx env | grep '^_='
_=/usr/bin/env
bash-4.3$ env _=xxx env | grep '^_='
_=xxx

In zsh, ARGV0 and STTY have special meanings in that context:

STTY=-echo cat

Runs cat with terminal echo disabled. And:

ARGV0=foo cmd

runs cmd with foo as its argv[0].

If you don't want that special processing, you have to use env.

Note that sudo supports:

sudo A=B cmd

It's not using the shell or env to do that. It does it by itself.

It can pass variables with any name except those starting with -.

Assignment is a shell construct whereas an equal sign in the argument of env has no special meaning to the shell, so A=$B cmd is safe whereas env A="$B" cmd (or sudo A="$B" cmd) require double quotes.

The A=B cmd syntax is only supported in the shells of the Bourne and rc families (not es though). In shells of the csh or fish families for instance, you have to resort to env.