Dans l'en-tête d'un script Bash, quelle est la différence entre ces deux instructions:
#!/usr/bin/env bash
#!/usr/bin/bash
Lorsque j'ai consulté la env
page de manuel , j'obtiens cette définition:
env - run a program in a modified environment
Qu'est-ce que ça veut dire?
Réponses:
L'exécution d'une commande
/usr/bin/env
a l'avantage de rechercher quelle que soit la version par défaut du programme dans votre environnement actuel .De cette façon, vous n'avez pas à le rechercher à un endroit spécifique du système, car ces chemins peuvent se trouver à différents emplacements sur différents systèmes. Tant qu'il est sur votre chemin, il le trouvera.
Un inconvénient est que vous ne pourrez pas passer plus d'un argument (par exemple, vous ne pourrez pas écrire
/usr/bin/env awk -f
) si vous souhaitez prendre en charge Linux, car POSIX est vague sur la façon dont la ligne doit être interprétée, et Linux interprète tout après le premier espace pour désigner un seul argument. Vous pouvez utiliser/usr/bin/env -S
sur certaines versions deenv
pour contourner ce problème, mais le script deviendra alors encore moins portable et se brisera sur des systèmes assez récents (par exemple, même Ubuntu 16.04 sinon plus tard).Un autre inconvénient est que, comme vous n'appelez pas un exécutable explicite, il peut y avoir des erreurs et des problèmes de sécurité des systèmes multi-utilisateurs (si quelqu'un a réussi à faire appeler son exécutable
bash
sur votre chemin, par exemple).Dans certaines situations, la première peut être préférée (comme exécuter des scripts python avec plusieurs versions de python, sans avoir à retravailler la ligne exécutable). Mais dans les situations où la sécurité est au centre, cette dernière serait préférable, car elle limite les possibilités d'injection de code.
la source
#!/usr/bin/env echo Hello
plaint:/usr/bin/env: echo Hello: No such file or directory
. Apparemment, il traiteecho Hello
comme un seul argument/usr/bin/env
.env
commande permet certainement de passer des arguments à la commande. Le problème est la sémantique de la#!
ligne, et cela dépend du noyau. Les noyaux Linux récents permettent des choses comme#!/usr/bin/env command args
, mais les noyaux Linux plus anciens et d'autres systèmes ne le permettent pas.L'utilisation
#!/usr/bin/env NAME
permet au shell de rechercher la première correspondance de NAME dans la variable d'environnement $ PATH. Cela peut être utile si vous ne connaissez pas le chemin absolu ou si vous ne voulez pas le rechercher.la source
Au lieu de définir explicitement le chemin d'accès à l'interpréteur comme dans
/usr/bin/bash/
, à l'aide de la commande env, l'interpréteur est recherché et lancé d'où qu'il se trouve pour la première fois. Cela a des avantages et des inconvénientsla source
Si les scripts shell commencent par
#!/bin/bash
, ils seront toujours exécutés avecbash
from/bin
. S'ils commencent cependant par#!/usr/bin/env bash
, ils chercherontbash
dans$PATH
puis commenceront par le premier qu'ils peuvent trouver.Pourquoi cela serait-il utile? Supposons que vous vouliez exécuter des
bash
scripts, qui nécessitent bash 4.x ou plus récent, mais votre système n'a quebash
3.x installé et actuellement votre distribution n'offre pas une version plus récente ou vous n'êtes pas administrateur et ne pouvez pas changer ce qui est installé sur ce système .Bien sûr, vous pouvez télécharger le code source bash et créer votre propre bash à partir de zéro, en le plaçant
~/bin
par exemple. Et vous pouvez également modifier votre$PATH
variable dans votre.bash_profile
fichier pour l'inclure~/bin
comme première entrée (PATH=$HOME/bin:$PATH
car~
elle ne sera pas développée dans$PATH
). Si vous appelez maintenantbash
, le shell va d'abord le chercher$PATH
dans l'ordre, il commence donc par~/bin
où il trouvera votre fichierbash
. La même chose se produit si les scripts recherchent l'bash
utilisation#!/usr/bin/env bash
, de sorte que ces scripts fonctionneraient désormais sur votre système à l'aide de votrebash
génération personnalisée .Un inconvénient est que cela peut conduire à un comportement inattendu, par exemple le même script sur la même machine peut s'exécuter avec différents interprètes pour différents environnements ou utilisateurs avec des chemins de recherche différents, provoquant toutes sortes de maux de tête.
Le plus gros inconvénient
env
est que certains systèmes n'autorisent qu'un seul argument, vous ne pouvez donc pas le faire#!/usr/bin/env <interpreter> <arg>
, car les systèmes le verront<interpreter> <arg>
comme un seul argument (ils le traiteront comme si l'expression était citée) etenv
rechercheront donc un interprète nommé<interpreter> <arg>
. Notez que ce n'est pas un problème de laenv
commande elle-même, qui a toujours permis de passer plusieurs paramètres mais avec l'analyseur shebang du système qui analyse cette ligne avant même d'appelerenv
. Pendant ce temps, cela a été corrigé sur la plupart des systèmes, mais si votre script veut être ultra portable, vous ne pouvez pas compter que cela a été corrigé sur le système que vous exécuterez.Il peut même avoir des implications sur la sécurité, par exemple s'il
sudo
n'a pas été configuré pour nettoyer l'environnement ou a$PATH
été exclu du nettoyage. Permettez-moi de le démontrer:/bin
Est généralement un endroit bien protégé, seulroot
peut y changer quoi que ce soit. Cependant, votre répertoire personnel n’est pas un programme que vous exécutez peut y apporter des modifications. Cela signifie qu'un code malveillant pourrait placer un fauxbash
dans un répertoire caché, modifiez votre.bash_profile
pour inclure ce répertoire dans votre$PATH
, afin que tous les scripts utilisant#!/usr/bin/env bash
finissent par fonctionner avec ce fauxbash
. Si çasudo
continue$PATH
, vous avez de gros ennuis.Par exemple, considérez qu'un outil crée un fichier
~/.evil/bash
avec le contenu suivant:Faisons un script simple
sample.sh
:Preuve de concept (sur un système où se
sudo
conserve$PATH
):Habituellement, les shells classiques doivent tous être situés dans
/bin
et si vous ne voulez pas les placer là pour une raison quelconque, ce n'est vraiment pas un problème de placer un lien symbolique/bin
qui pointe vers leur emplacement réel (ou peut/bin
- être lui - même est un lien symbolique), donc J'irais toujours avec#!/bin/sh
et#!/bin/bash
. Il y a trop de choses qui se briseraient si elles ne fonctionnaient plus. Ce n'est pas que POSIX aurait besoin de ces positions (POSIX ne standardise pas les noms de chemin et donc il ne standardise même pas du tout la fonctionnalité shebang) mais ils sont si courants que même si un système ne proposait pas de/bin/sh
, il comprendrait probablement#!/bin/sh
et savoir quoi en faire et que ce ne soit que pour la compatibilité avec le code existant.Mais pour les interprètes optionnels plus modernes et non standard comme Perl, PHP, Python ou Ruby, il n'est pas vraiment spécifié où ils devraient être situés. Ils peuvent être en ,
/usr/bin
mais ils peuvent aussi bien être/usr/local/bin
ou dans une branche de la hiérarchie complètement différente (/opt/...
,/Applications/...
, etc.). C'est pourquoi ceux-ci utilisent souvent la#!/usr/bin/env xxx
syntaxe shebang.la source
Je le trouve utile, car quand je ne connaissais pas env, avant de commencer à écrire un script, je faisais ceci:
et puis je modifiais cette ligne dans le fichier en shebang.
Je faisais cela, parce que je ne me souvenais pas toujours où se trouve nodejs sur mon ordinateur - / usr / bin / ou / bin /, donc pour moi,
env
c'est très utile. Peut-être qu'il y a des détails avec ça, mais c'est ma raisonla source