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 Answer
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.