GNU/Linux >> Linux Esercitazione >  >> Linux

Qual è la differenza tra #!/usr/bin/env bash e #!/usr/bin/bash?

Se gli script della shell iniziano con #!/bin/bash , funzioneranno sempre con bash da /bin . Se invece iniziano con #!/usr/bin/env bash , cercheranno bash in $PATH e quindi iniziare con il primo che riescono a trovare.

Perché questo sarebbe utile? Supponi di voler eseguire bash script, che richiedono bash 4.xo più recente, ma il tuo sistema ha solo bash 3.x installato e attualmente la tua distribuzione non offre una versione più recente o non sei un amministratore e non puoi modificare ciò che è installato su quel sistema.

Naturalmente, puoi scaricare il codice sorgente di bash e creare la tua bash da zero, posizionandola in ~/bin Per esempio. E puoi anche modificare il tuo $PATH variabile nel tuo .bash_profile file per includere ~/bin come prima voce (PATH=$HOME/bin:$PATH come ~ non si espanderà in $PATH ). Se ora chiami bash , la shell lo cercherà prima in $PATH in ordine, quindi inizia con ~/bin , dove troverà il tuo bash . La stessa cosa accade se gli script cercano bash utilizzando #!/usr/bin/env bash , quindi questi script ora funzionerebbero sul tuo sistema utilizzando il tuo bash personalizzato costruire.

Uno svantaggio è che questo può portare a comportamenti imprevisti, ad es. 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 grattacapo.

Il più grande svantaggio con 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 cercherà un interprete chiamato <interpreter> <arg> . Nota 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 riga prima ancora di chiamare env . Nel frattempo, questo è stato corretto sulla maggior parte dei sistemi, ma se il tuo script vuole essere ultraportatile, non puoi fare affidamento sul fatto che sia stato risolto sul sistema che eseguirai.

Può anche avere implicazioni sulla sicurezza, ad es. if sudo non è stato configurato per pulire l'ambiente o $PATH è stato escluso dalla bonifica. Lasciatemi dimostrare questo:

Di solito /bin è un luogo ben protetto, solo root è in grado di cambiare qualsiasi cosa lì. La tua home directory non è, tuttavia, qualsiasi programma che esegui è in grado di apportare modifiche ad essa. Ciò significa che il codice dannoso potrebbe inserire un falso bash in qualche directory nascosta, modifica il tuo .bash_profile per includere quella directory nel tuo $PATH , quindi tutti gli script utilizzano #!/usr/bin/env bash finirà per funzionare con quel falso bash . Se sudo mantiene $PATH , sei in grossi guai.

Per 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 "[email protected]"

Facciamo un semplice script sample.sh :

#!/usr/bin/env bash

echo "Hello World"

Proof of concept (su un sistema in cui sudo mantiene $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 trovarsi tutte in /bin e se non vuoi metterli lì per qualsiasi motivo, non è davvero un problema inserire un collegamento simbolico in /bin che indica le loro posizioni reali (o forse /bin è di per sé un collegamento simbolico), quindi andrei sempre con #!/bin/sh e #!/bin/bash . C'è solo troppo che si romperebbe se questi non funzionassero più. Non è che POSIX richieda queste posizioni (POSIX non standardizza i nomi di percorso e quindi non standardizza nemmeno la funzione shebang) ma sono così comuni che anche se un sistema non offrisse un /bin/sh , probabilmente capirebbe ancora #!/bin/sh e sapere cosa farne e che sia solo per compatibilità con il codice esistente.

Ma per interpreti più moderni, non standard e opzionali come Perl, PHP, Python o Ruby, non è realmente specificato da nessuna parte dove dovrebbero trovarsi. Potrebbero essere in /usr/bin ma potrebbero anche essere in /usr/local/bin o in un ramo gerarchico completamente diverso (/opt/... , /Applications/... , eccetera.). Ecco perché spesso usano il #!/usr/bin/env xxx sintassi shebang.


Usando #!/usr/bin/env NAME fa in modo che la shell cerchi la prima corrispondenza di NAME nella variabile d'ambiente $PATH. Può essere utile se non sei a conoscenza del percorso assoluto o non vuoi cercarlo.


Esecuzione di un comando tramite /usr/bin/env ha il vantaggio di cercare qualunque sia la versione predefinita del programma nel tuo attuale env ferro.

In questo modo, non è necessario cercarlo in un punto specifico del sistema, poiché tali percorsi potrebbero trovarsi in posizioni diverse su sistemi diversi. Finché è sul tuo cammino, lo troverà.

Uno svantaggio è che non sarai in grado di passare più di un argomento (ad esempio non sarai in grado di scrivere /usr/bin/env awk -f ) se desideri supportare Linux, poiché POSIX è vago su come interpretare la linea e Linux interpreta tutto dopo il primo spazio per denotare un singolo argomento. Puoi usare /usr/bin/env -S su alcune versioni di env per aggirare questo problema, ma poi lo script diventerà ancora meno portabile e si romperà su sistemi abbastanza recenti (ad esempio anche Ubuntu 16.04 se non successivo).

Un altro svantaggio è che dal momento che non stai chiamando un eseguibile esplicito, ha il potenziale per errori e su sistemi multiutente problemi di sicurezza (se qualcuno è riuscito a ottenere il proprio eseguibile chiamato bash nel tuo percorso, per esempio).

#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash     #gives you explicit control on a given system of what executable is called

In alcune situazioni, potrebbe essere preferibile il primo (come l'esecuzione di script Python con più versioni di Python, senza dover rielaborare la riga eseguibile). Ma in situazioni in cui la sicurezza è l'obiettivo, quest'ultimo sarebbe preferito, in quanto limita le possibilità di iniezione di codice.


Linux
  1. /usr/bin Vs /usr/local/bin Su Linux?

  2. Qual è la differenza tra /sbin/nologin e /bin/false?

  3. La differenza tra /opt e /usr/local?

  4. Qual è il motivo per cui uno Shebang punta a /bin/sh piuttosto che a /bin/bash?

  5. Linux – Unire /usr/bin e /usr/sbin in /bin (gnu/linux)?

Quando devo usare #!/bin/bash e quando #!/bin/sh?

Differenza tra /bin e /usr/bin

Qual è la differenza tra /tmp e /run?

I siti web dovrebbero vivere in /var/ o /usr/ in base all'utilizzo consigliato?

Cos'è /usr/bin/[?

#!/bin/sh vs #!/bin/bash per la massima portabilità