Si les scripts shell commencent par #!/bin/bash
, ils seront toujours exécutés avec bash
from /bin
. S'ils commencent cependant par #!/usr/bin/env bash
, ils chercheront bash
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 que bash
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 maintenant bash
, le shell va d'abord le chercher $PATH
dans l'ordre, il commence donc par ~/bin
où il trouvera votre fichier bash
. 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 votre bash
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) et env
rechercheront donc un interprète nommé <interpreter> <arg>
. Notez que ce n'est pas un problème de la env
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'appeler env
. 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é, seul root
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 faux bash
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 faux bash
. Si ça sudo
continue $PATH
, vous avez de gros ennuis.
Par exemple, considérez qu'un outil crée un fichier ~/.evil/bash
avec le contenu suivant:
#!/bin/bash
if [ $EUID -eq 0 ]; then
echo "All your base are belong to us..."
# We are root - do whatever you want to do
fi
/bin/bash "$@"
Faisons un script simple sample.sh
:
#!/usr/bin/env bash
echo "Hello World"
Preuve de concept (sur un système où se sudo
conserve $PATH
):
$ ./sample.sh
Hello World
$ sudo ./sample.sh
Hello World
$ export PATH="$HOME/.evil:$PATH"
$ ./sample.sh
Hello World
$ sudo ./sample.sh
All your base are belong to us...
Hello World
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.