Se gli script della shell iniziano con #!/bin/bash
, verranno sempre eseguiti con bash
da /bin
. Se tuttavia iniziano con #!/usr/bin/env bash
, cercheranno bash
in $PATH
e poi inizieranno con il primo che riescono a trovare.
Perché sarebbe utile? Supponiamo che tu voglia eseguire bash
script che richiedono bash 4.xo bash
versioni successive, ma il tuo sistema ha solo 3.x installato e attualmente la tua distribuzione non offre una versione più recente o non sei un amministratore e non puoi cambiare ciò che è installato su quel sistema .
Naturalmente, puoi scaricare il codice sorgente di bash e creare il tuo bash da zero, posizionandolo ad ~/bin
esempio. E puoi anche modificare la tua $PATH
variabile nel tuo .bash_profile
file per includerla ~/bin
come prima voce ( PATH=$HOME/bin:$PATH
poiché ~
non si espanderà $PATH
). Se ora chiami bash
, la shell lo cercherà prima $PATH
in ordine, quindi inizia con ~/bin
dove troverà il tuo bash
. La stessa cosa accade se gli script cercano di bash
utilizzarli #!/usr/bin/env bash
, quindi questi script ora funzionerebbero sul tuo sistema usando la tua bash
build personalizzata .
Un aspetto negativo è che ciò può portare a comportamenti imprevisti, ad esempio lo stesso script sulla stessa macchina può essere eseguito con interpreti diversi per ambienti diversi o utenti con percorsi di ricerca diversi, causando ogni tipo di mal di testa.
Il più grande svantaggio env
è che alcuni sistemi consentiranno solo un argomento, quindi non puoi farlo #!/usr/bin/env <interpreter> <arg>
, poiché i sistemi vedranno <interpreter> <arg>
come un argomento (lo tratteranno come se l'espressione fosse citata) e quindi env
cercheranno un interprete chiamato <interpreter> <arg>
. Si noti che questo non è un problema del env
comando stesso, che ha sempre consentito il passaggio di più parametri ma con il parser shebang del sistema che analizza questa linea prima di chiamare env
. Nel frattempo questo è stato risolto sulla maggior parte dei sistemi, ma se il tuo script vuole essere ultra portatile, non puoi fare affidamento sul fatto che questo è stato corretto sul sistema che eseguirai.
Può anche avere implicazioni per la sicurezza, ad esempio se sudo
non è stato configurato per pulire l'ambiente o è $PATH
stato escluso dalla pulizia. Lasciami dimostrare questo:
Di solito /bin
è un posto ben protetto, root
è solo in grado di cambiare qualcosa lì. La tua home directory non è, tuttavia, nessun programma che esegui è in grado di apportarvi modifiche. Ciò significa che il codice dannoso potrebbe inserire un falso bash
in una directory nascosta, modificarlo .bash_profile
per includerlo nella propria directory $PATH
, quindi tutti gli script utilizzati #!/usr/bin/env bash
finiranno per essere eseguiti con quel falso bash
. Se sudo
continua $PATH
, sei in grossi guai.
Ad esempio, considera che uno strumento crea un file ~/.evil/bash
con il seguente contenuto:
#!/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 "$@"
Facciamo un semplice script sample.sh
:
#!/usr/bin/env bash
echo "Hello World"
Prova del concetto (su un sistema in cui sudo
continua $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
Di solito le shell classiche dovrebbero essere tutte localizzate /bin
e se non vuoi metterle lì per qualsiasi motivo, non è davvero un problema posizionare un link simbolico in /bin
quel punto verso le loro posizioni reali (o forse /bin
è esso stesso un link simbolico), quindi Vorrei sempre andare con #!/bin/sh
e #!/bin/bash
. C'è solo troppo che si spezzerebbe se non funzionasse più. Non è che POSIX richiederebbe questa posizione (POSIX non standardizza i nomi dei percorsi e quindi non uniforma affatto la funzione shebang) ma sono così comuni, che anche se un sistema non offrirebbe un /bin/sh
, probabilmente capirà comunque #!/bin/sh
e sapere cosa farne e potrebbe essere solo per compatibilità con il codice esistente.
Ma per interpreti più moderni, non standard, opzionali come Perl, PHP, Python o Ruby, non è specificato da nessuna parte dove dovrebbero trovarsi. Essi possono essere in /usr/bin
ma possono anche essere in /usr/local/bin
o in un ramo gerarchia di completamente diverso ( /opt/...
, /Applications/...
, ecc). Ecco perché questi usano spesso la #!/usr/bin/env xxx
sintassi di shebang.