Env ou pas env

32

Quelle est la différence entre la commande

$ env FOO=bar baz

et

$ FOO=bar baz

Quel effet enva?

August Karlstrom
la source
4
En quelque sorte une question secondaire, mais comment appelle-t-on la fonctionnalité elle-même lorsque vous définissez une variable d'environnement pour une seule sous-commande comme celle-ci? J'ai toujours eu du mal à trouver des informations à ce sujet parce que je ne sais pas comment ça s'appelle.
John Cromartie
1
@ JohnCromartie, vous devriez poser cette question sous forme de question.
cjm
1
Pour bash, c'est documenté ici: gnu.org/software/bash/manual/…
glenn jackman
2
@JohnCromartie C'est un composant optionnel de chaque commande shell, il se trouve donc dans la section "Commandes simples" de la plupart des manuels shell. Pour POSIX, ce serait ici . glenn a déjà lié pour vous la section analogue du manuel bash.
jw013
Définir une variable qui n'existe pas via une affectation crée une variable shell. Le paramétrage via ENV ou l'exportation de la variable la pousse dans l'environnement d'exécution du shell. La modification de la valeur d'une variable existante met à jour la valeur de l'environnement d'exécution, le cas échéant, sinon changez-la dans les variables internes du shell.
Johan

Réponses:

26

Ils sont fonctionnellement équivalents.

La principale différence est qu’il env FOO=bar bazs’agit d’invoquer un processus intermédiaire entre le shell et baz, comme avec FOO=bar bazle shell, directement baz.
Donc, à cet égard, FOO=bar bazest préféré.

Les seules situations où je me trouve à utiliser env FOO=barsont celles où je dois passer une commande à une autre.
Comme exemple spécifique, disons que j'ai un script d'encapsuleur qui effectue certaines modifications de l'environnement, puis appelle execla commande qui lui a été transmise, telle que:

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

Si vous l'exécutez en tant que myscript FOO=bar baz, execcela générera une erreur car elle exec FOO=bar bazn'est pas valide.
Au lieu de cela, vous l'appelez en tant que myscript env FOO=bar bazqui est exécuté en tant que exec env FOO=bar baz, et est parfaitement valide.

Patrick
la source
1
Vous pouvez le faire FOO=bar exec baz, alors vous n’avez pas besoin envde votre dernier point.
Stéphane Chazelas
Lorsque vous executilisez quelque chose, utilise-t-il votre environnement actuel?
Glenn Jackman
1
Idem @StephaneChazelas, et vous pouvez également sudo FOO=bar bazpasser des variables d'environnement sans avoir besoin de env.
Mike Miller
1
@ StephaneChazelas qui ne fonctionne que si je veux mettre FOO=bardans le script. Si ce FOOn'est pas toujours le cas bar, je ne veux pas le coder en dur, mais plutôt le transmettre.
Patrick
@glennjackman oui, tant que les variables sont exportées ou passées avant le exec, tel que FOO=bar exec baz.
Patrick
14

Dans cet exemple particulier, il n'y a pas de différence réelle, en supposant que votre shell est un shell compatible POSIX, et en supposant qu'il bazs'agisse d'un exécutable et non d'un shell intégré.

Si votre shell n’est pas compatible POSIX, par exemple cshou tcsh, la syntaxe

FOO=bar baz

ne fonctionne pas et il n’existe pas de syntaxe de shell équivalente. Pour ces shells, la envcommande est le seul moyen de remplacer ou d’injecter des variables d’environnement pour une seule commande.

Si bazest un shell intégré, disons fcpar exemple, alors envne donnera pas les mêmes résultats, car envexécute un nouveau processus au lieu d'être exécuté directement par le shell de commande. De plus, il n'y a pas fcexécutable, il ne peut être exécuté comme une commande du shell en raison de la façon dont elle interagit avec l'environnement shell, et ainsi le envsera jamais travailler avec un builtin comme fc.

En outre, envoffre l' -ioption qui vous permet de démarrer une commande dans un environnement vide avec uniquement un ensemble spécifié de variables d'environnement. Cela envpeut donc être très utile pour démarrer des processus dans des environnements désinfectés, par exemple

env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz
Mike Miller
la source
Quand j’utilisais tcshj’écrivais (setenv FOO bar; baz)pour obtenir la fonction équivalente.
Barmar
6

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

VAR=value cmd args > redirs

En tant que fonctionnalité shell (Bourne / POSIX), le nom des variables d’environnement que vous transmettez est limité cmd. Ils doivent être des noms de variables shell valides et ne doivent pas être des variables en lecture seule ou spéciales du 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 le faire). Ou:

env SHELLOPTS=xtrace cmd

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

Notez que envvous ne pouvez toujours pas transmettre une chaîne de variable d'environnement qui ne contient pas de =(non que vous ne souhaitiez pas le faire non plus).

Stéphane Chazelas
la source
2

Une utilisation de envest de permettre la $PATHrecherche des exécutables dans les lignes shebang (car envconsidère $PATHlors de la recherche de l'exécutable). Ceci est utile si l'exécutable que vous voulez appeler peut se trouver à différents endroits sur différentes machines. Par exemple,

#!/usr/bin/env perl

dans la première ligne d'un script avec un bit exécutable, ce script sera exécuté avec Perl, qu'il soit installé dans, /usr/bin/perldans /usr/local/bin/perlou à un endroit complètement différent, tant que le répertoire est dans le chemin.

Bien sûr, cette recherche de chemin comporte un risque supplémentaire, mais le risque n’est pas plus grand que si vous aviez écrit explicitement perl yourscript.pl, ce qui permet également de rechercher perl dans le chemin de recherche.

celtschk
la source
2

Une autre fois où il envest vraiment utile est de contrôler totalement l’environnement. Je lance un programme serveur (Informix, au cas où vous ne pourriez pas deviner) dont je veux contrôler complètement l’environnement. Je l'exécute en utilisant envà la fin d'un script qui définit un ensemble de variables sur les 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' -ioption zappe l'environnement existant. Les VAR=valueoptions suivantes définissent les variables d’environnement que je souhaite définir; le nom du programme est dedans $ONINIT, et tous les arguments de ligne de commande sont passés verbatim avec "$@".

La ${IXH:+INFORMIXSQLHOSTS="$IXH"}construction ne fait que passer INFORMIXSQLHOSTS="$IXH"à envif si elle $IXHest définie sur une valeur non vide.

Jonathan Leffler
la source