Env ou env

Quelle est la différence entre la command

$ env FOO=bar baz 

et

 $ FOO=bar baz 

Quel effet ont env ?

Ils sont fonctionnellement équivalents.

La principale différence est que env FOO=bar baz implique l'invocation d'un process intermédiaire entre shell et baz , où comme avec FOO=bar baz le shell invoque directement baz .
Donc, à cet égard, FOO=bar baz est préféré.

Les seules situations où je me trouve en utilisant env FOO=bar in est où je dois passer une command à une autre command.
Comme exemple spécifique, disons que j'ai un script wrapper qui effectue quelques modifications de l'environnement, puis appelle exec sur la command qui lui a été transmise, par exemple:

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

Si vous l'exécutez comme myscript FOO=bar baz , l' exec lancera une erreur car exec FOO=bar baz est invalide.
Au lieu de cela, vous l'appelez comme myscript env FOO=bar baz qui s'exécute comme exec env FOO=bar baz , et est parfaitement valide.

Dans cet exemple particulier, il n'y a pas de différence effective, en supposant que votre shell est un shell compatible POSIX, et en supposant que baz est un exécutable et non un shell embedded.

Si votre shell n'est pas un shell compatible POSIX, par exemple csh ou tcsh , la syntaxe

 FOO=bar baz 

ne fonctionne pas et il n'y a pas de syntaxe de shell équivalente. Pour ces shells, la command env est la seule façon de surcharger ou d'injecter des variables d'environnement pour une seule command.

Si baz est un shell embedded, disons fc par exemple, env ne donnera pas les mêmes résultats car env exécute un nouveau process au lieu d'être exécuté directement par le shell de command. De plus, il n'y a pas d'exécutable fc , il ne peut être exécuté en tant que shell qu'en raison de la façon dont il interagit avec l'environnement shell, donc env ne fonctionnera jamais avec un builtin comme fc .

De plus, env offre l'option -i qui vous permet de démarrer une command dans un environnement vide avec seulement un set spécifié de variables d'environnement. Donc env peut être très utile pour démarrer des process dans des environnements aseptisés, par exemple

 env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz 

En plus de ce qui a déjà été dit

 VAR=value cmd args > redirs 

étant une fonctionnalité shell (Bourne / POSIX), vous êtes limité au nom des variables d'environnement que vous transmettez à cmd . Ils doivent être des noms de variables de shell valides et ne doivent pas être en lecture seule ou des variables spéciales pour le shell.

Par exemple, vous ne pouvez pas faire:

 1=foo cmd 

Ou

 +++=bar cmd 

bash ne vous permet pas de faire:

 SHELLOPTS=xtrace cmd 

Alors que vous pouvez faire:

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

(pas que vous voulez ou devriez vouloir faire cela). Ou:

 env SHELLOPTS=xtrace cmd 

(J'ai parfois besoin de faire ça).

Notez qu'avec env vous ne pouvez toujours pas passer une string de variable d'environnement qui ne contient pas de = (pas que vous voudriez le faire non plus).

Une utilisation de env est de permettre la search $PATH des exécutables dans les lignes shebang (car env considère le $PATH lors de la search de l'exécutable). Ceci est utile si l'exécutable que vous voulez appeler peut se find à différents endroits sur différentes machines. Par exemple,

 #!/usr/bin/env perl 

dans la première ligne d'un script avec un jeu de bits exécutable exécutera ce script avec Perl, qu'il soit installé dans /usr/bin/perl ou dans /usr/local/bin/perl ou dans un endroit complètement différent, tant que le directory est dans le path.

Bien sûr, cette search de path s'accompagne d'un risque supplémentaire, mais le risque n'est pas plus grand que si vous aviez explicitement écrit perl yourscript.pl , qui search également perl dans le path de search.

Une autre fois où env est vraiment utile est si vous voulez contrôler l'environnement complètement. Je cours un programme server (Informix, au cas où vous ne pouvez pas deviner) dont l'environnement je veux contrôler complètement. Je le lance en utilisant env à la fin d'un script qui définit un set de variables aux valeurs correctes:

 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 "$@" 

L'option -i zaps l'environnement existant. Les options VAR=value définissent les variables d'environnement que je veux définir; le nom du programme est dans $ONINIT , et les arguments de command line sont passés par verbatim avec "$@" .

La construction ${IXH:+INFORMIXSQLHOSTS="$IXH"} passe uniquement INFORMIXSQLHOSTS="$IXH" à env si $IXH est défini sur une valeur non vide.