Quelle est la différence entre set, export et env et quand dois-je les utiliser?

112

De temps en temps, je rédige un script bash et il me semble qu'il existe plusieurs façons de définir une variable:

key=value
env key=value
export key=value

Lorsque vous êtes dans un script ou une seule commande (par exemple, je vais souvent chaîner une variable avec un lanceur Wine pour définir le préfixe Wine correct), celles-ci semblent être complètement interchangeables, mais ce ne peut certainement pas être le cas.

Quelle est la différence entre ces trois méthodes et pouvez-vous me donner un exemple du moment où je souhaiterais spécifiquement utiliser chacune d'elles?

Relativement liée à Quelle est la différence entre `VAR = ...` et `export VAR = ...`? mais je veux savoir comment cela envs'inscrit aussi, et quelques exemples montrant les avantages de chacun seraient bien aussi :)

Oli
la source
5
Notez que export key=valuec'est une syntaxe étendue et ne doit pas être utilisé dans des scripts portables (c'est-à-dire #! /bin/sh).
Simon Richter

Réponses:

110

Considérons un exemple spécifique. La grepcommande utilise une variable d'environnement appelée GREP_OPTIONSpour définir les options par défaut.

Maintenant. Étant donné que le fichier test.txtcontient les lignes suivantes:

line one
line two

l'exécution de la commande grep one test.txtretournera

line one

Si vous exécutez grep avec l’ -voption, elle renverra les lignes qui ne correspondent pas, ainsi le résultat sera

line two

Nous allons maintenant essayer de définir l’option avec une variable environnementale.

  1. Les variables d'environnement définies sans exportne seront pas héritées de l'environnement des commandes que vous appelez.

    GREP_OPTIONS='-v'
    grep one test.txt
    

    Le résultat:

    line one

    De toute évidence, l'option -vn'a pas été transmise à grep.

    Vous souhaitez utiliser ce formulaire lorsque vous définissez une variable à utiliser uniquement par le shell, par exemple si for i in * ; dovous ne souhaitez pas exporter $i.

  2. Cependant, la variable est transmise à l’environnement de cette ligne de commande, vous pouvez donc effectuer cette opération.

    GREP_OPTIONS='-v' grep one test.txt

    qui retournera le prévu

    line two

    Vous utilisez ce formulaire pour modifier temporairement l'environnement de cette instance particulière du programme lancé.

  3. L'exportation d'une variable entraîne l'héritage de la variable:

    export GREP_OPTIONS='-v'
    grep one test.txt
    

    revient maintenant

    line two

    C’est le moyen le plus courant de définir des variables pour l’utilisation de processus lancés ultérieurement dans un shell.

  4. Tout a été fait à Bash. exportest un bash intégré; VAR=whateverest la syntaxe bash. envd'autre part, est un programme en soi. Quand envest appelé, les choses suivantes se produisent:

    1. La commande envest exécutée comme un nouveau processus
    2. env modifie l'environnement, et
    3. appelle la commande fournie en argument. Le envprocessus est remplacé par le commandprocessus.

    Exemple:

    env GREP_OPTIONS='-v' grep one test.txt

    Cette commande lancera deux nouveaux processus: (i) env et (ii) grep (en réalité, le deuxième processus remplacera le premier). Du point de vue du grepprocessus, le résultat est identique à l’exécution

    GREP_OPTIONS='-v' grep one test.txt

    Cependant, vous pouvez utiliser cet idiome si vous êtes en dehors de bash ou si vous ne souhaitez pas lancer un autre shell (par exemple, lorsque vous utilisez la exec()famille de fonctions plutôt que l' system()appel).

Note complémentaire sur #!/usr/bin/env

C'est aussi pourquoi l'idiome #!/usr/bin/env interpreterest utilisé plutôt que #!/usr/bin/interpreter. envne nécessite pas un chemin d'accès complet à un programme, car il utilise la execvp()fonction qui parcourt la PATHvariable, comme le fait un shell, puis se remplace par la commande exécutée. Ainsi, il peut être utilisé pour savoir où un interprète (comme perl ou python) "se repose" sur le chemin.

Cela signifie également qu'en modifiant le chemin actuel, vous pouvez influencer quelle variante python sera appelée. Cela rend possible ce qui suit:

echo -e '#!/usr/bin/bash\n\necho I am an evil interpreter!' > python
chmod a+x ./python
export PATH=.
calibre

au lieu de lancer Calibre, se traduira par

I am an evil interpreter!
janvier
la source
Pourquoi GREP_OPTIONS = '- v' grep one test.txt fonctionne-t-il? Je pensais qu'il fallait un point-virgule après '-v' (mais je l'ai essayé et ça marche en fait.)
Joe
2
Parce qu'avec un point-virgule, il est interprété comme deux commandes bash distinctes; le premier définit la variable (sans l'exporter) et le second commence par un environnement dans lequel la variable n'a pas été exportée. Sans le point-virgule, toutefois, il s'agit d'une commande (grep), précédée de la définition d'un environnement local.
janvier
D'où envproviennent toutes les variables ? Je veux dire quand vous ouvrez un nouveau shell, vous avez toujours quelques variables. Donc, certains programmes doivent les avoir export, non?
Pithikos
1
Les variables d'environnement @Pithikos sont définies par "l'obtention d'un environnement". Par défaut, bash utilisera une base de données système (ou profile.d ou bash_profile) pour l’ensemble du système. Ensuite, il source votre utilisateur ~ / .bashrc (et / ou ~ / .bash_profile). L'un ou l'autre de ces fichiers peut contenir des commandes bash pour générer d'autres scripts. Vous pouvez donc avoir des variables d'environnement provenant de partout.
Eric
5
Qu'en est- il set var=blah?
CMCDragonkai