Se gli script della shell iniziano con #!/bin/bash, verranno sempre eseguiti con bashda /bin. Se tuttavia iniziano con #!/usr/bin/env bash, cercheranno bashin $PATHe poi inizieranno con il primo che riescono a trovare.
Perché sarebbe utile? Supponiamo che tu voglia eseguire bashscript che richiedono bash 4.xo bashversioni 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 ~/binesempio. E puoi anche modificare la tua $PATHvariabile nel tuo .bash_profilefile per includerla ~/bincome prima voce ( PATH=$HOME/bin:$PATHpoiché ~non si espanderà $PATH). Se ora chiami bash, la shell lo cercherà prima $PATHin ordine, quindi inizia con ~/bindove troverà il tuo bash. La stessa cosa accade se gli script cercano di bashutilizzarli #!/usr/bin/env bash, quindi questi script ora funzionerebbero sul tuo sistema usando la tua bashbuild 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 envcercheranno un interprete chiamato <interpreter> <arg>. Si noti che questo non è un problema del envcomando 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 sudonon è stato configurato per pulire l'ambiente o è $PATHstato 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 bashin una directory nascosta, modificarlo .bash_profileper includerlo nella propria directory $PATH, quindi tutti gli script utilizzati #!/usr/bin/env bashfiniranno per essere eseguiti con quel falso bash. Se sudocontinua $PATH, sei in grossi guai.
Ad esempio, considera che uno strumento crea un file ~/.evil/bashcon 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 sudocontinua $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 /bine se non vuoi metterle lì per qualsiasi motivo, non è davvero un problema posizionare un link simbolico in /binquel punto verso le loro posizioni reali (o forse /binè esso stesso un link simbolico), quindi Vorrei sempre andare con #!/bin/she #!/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/she 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/binma possono anche essere in /usr/local/bino in un ramo gerarchia di completamente diverso ( /opt/..., /Applications/..., ecc). Ecco perché questi usano spesso la #!/usr/bin/env xxxsintassi di shebang.