Perché #! / Usr / bin / env bash è superiore a #! / Bin / bash?


212

Ho visto in diversi punti, compresi i consigli su questo sito ( qual è il Bash shebang preferito? ), Da usare #!/usr/bin/env bashin preferenza #!/bin/bash. Ho anche visto un individuo intraprendente suggerire che l'uso #!/bin/bashfosse sbagliato e la funzionalità bash si perderebbe così.

Detto questo, utilizzo bash in un ambiente di test strettamente controllato in cui ogni unità in circolazione è essenzialmente un clone di una singola unità master. Comprendo l'argomento della portabilità, sebbene non sia necessariamente applicabile nel mio caso. C'è qualche altro motivo da preferire #!/usr/bin/env bashrispetto alle alternative e, supponendo che la portabilità fosse una preoccupazione, c'è qualche motivo per usarne la funzionalità?


7
Non è necessariamente migliore. Vedi questa domanda e la mia risposta su unix.stackexchange.com. (Vorrei votare per chiudere questo come duplicato, ma non credo che tu possa farlo attraverso i siti.)
Keith Thompson,

2
Oltre alla risposta di @ zigg, envpotrebbe non trovarsi in /usr/bin. I commenti di Shebang sono del tutto una cattiva idea IMHO. Se l'interprete di script predefinito non gestisce i commenti shebang, è solo un commento. Tuttavia, se sai che l'interprete di script è in grado di gestire i commenti shebang e conosci il percorso per bash, non c'è motivo di non invocarlo usando il suo percorso assoluto a meno che il percorso non sia troppo lungo (improbabile), o potresti portarlo su un sistema che non ha bash situato in / bin. Poi di nuovo, le avvertenze che ho menzionato in precedenza si applicano in quel caso poiché comporta la portabilità.

1
@KeithThompson, grazie per il link. Forse la mia ricerca di una risposta prima di pubblicare la domanda era un po 'stretta. Il mio take-away da tutto questo: (1) linux / unix / posix / etc ... è grigio, e (2) chiunque affermi di avere assolutamente la risposta giusta ha assolutamente la risposta giusta per il loro particolare scenario.
spugm1r3,

3
Il comportamento di molte cose in POSIX / Unix è ben definito. Le posizioni non sono sempre così nette. Qualcosa deve esistere come /etco /bin/sh. bashè un componente aggiuntivo per la maggior parte dei sistemi simili a Unix. È solo Linux dove bashè garantito che si trovi /bine molto probabilmente anche collegato come /bin/sh. Da quando Linux è diventato il moderno Unix di fatto per molte persone, il fatto che esistano sistemi diversi da Linux è stato dimenticato. Nella mia risposta di seguito ho assunto Linux perché hai detto bash. Molte delle scatole BSD con cui ho lavorato non lo hanno nemmeno installato.
Sean Perry,

2
@Keith - Nel caso di Bash (al contrario di Python nelle altre domande) ... OpenBSD non ha un /bin/bash. Bash non è installato per impostazione predefinita. Se lo vuoi, devi farlo pkg install bash. Una volta installato, si trova in /usr/local/bin/bash. Su /bin/bashOpenBSD non è installato nulla . Un colpo di #!/bin/basherrore di volontà, e #!/usr/bin/env bashavrà successo.
1919

Risposte:


229

#!/usr/bin/envRicerche PATHper bash, e bashnon è sempre /bin, in particolare su sistemi non Linux. Ad esempio, sul mio sistema OpenBSD, è presente /usr/local/bin, poiché è stato installato come pacchetto opzionale.

Se sei assolutamente sicuro che lo bashsia /bine lo sarà sempre, non c'è nulla di male nel metterlo direttamente nel tuo shebang, ma lo sconsiglio perché gli script e i programmi hanno tutti vite oltre ciò che inizialmente crediamo che avranno.


29
che dire della envposizione? POSIX non lo forza.
Julio Guerra,

1
@JulioGuerra Proprio come avere un binario /usr/lib/sendmail(o, più recentemente, /usr/sbin/sendmail) disponibile per elaborare la posta, è nell'interesse di un sistema simile a Unix avere /usr/bin/envperché l'enb shebang è una pratica così comune. È un'interfaccia standard di fatto.
zigg,

8
@zigg È così UN * X ... <-: Voglio dire, è nel loro interesse avere una posizione standard per env, ma in qualche modo non avere una posizione standard (che può essere solo un soft link) per bash. Per non parlare del perché, quindi, hashbang non accetta solo #!bashe usa il PATH, invece di fare esattamente lo stesso con env. Immagino che non sia abbastanza confuso per i principianti.
ddekany,

1
@JulioGuerra Secondo wikipedia sei vero: non è "garantito". Invece, sembra "più probabile". Wikipedia dice This mostly works because the path /usr/bin/env is commonly used for the env utilityqui en.wikipedia.org/wiki/Shebang_(Unix) - Dobbiamo confidare envnell'essere lì "probabilmente" in tutti i sistemi.
Xavi Montero,

2
@XaviMontero: ho usato un sistema in cui si envtrovava /bin, non in /usr/bin(non sono sicuro di quale, probabilmente SunOS 4). In questi giorni è molto probabile /usr/bin/envche sia disponibile, proprio per la popolarità #!/usr/bin/envdell'hacking.
Keith Thompson,

39

La posizione standard di bash è /bine sospetto che sia vera su tutti i sistemi. Tuttavia, cosa succede se non ti piace quella versione di bash? Ad esempio, voglio usare bash 4.2, ma la bash sul mio Mac è a 3.2.5.

Potrei provare a reinstallare Bash /binma potrebbe essere una cattiva idea. Se aggiorno il mio sistema operativo, verrà sovrascritto.

Tuttavia, potrei installare bash /usr/local/bin/bashe impostare il mio PERCORSO su:

PATH="/usr/local/bin:/bin:/usr/bin:$HOME/bin"

Ora, se lo specifico bash, non ottengo il vecchio rozzo in /bin/bash, ma il nuovo, più lucido in /usr/local/bin. Bello!

Tranne che i miei script shell hanno quel !# /bin/bashshebang. Quindi, quando eseguo i miei script di shell, ottengo quella versione vecchia e scadente di bash che non ha nemmeno array associativi.

utilizzando /usr/bin/env bash utilizzerò la versione di bash trovata nel mio PERCORSO. Se imposto il mio PERCORSO, in modo che /usr/local/bin/bashvenga eseguito, questa è la bash che i miei script useranno.

È raro vederlo con bash, ma è molto più comune con Perl e Python:

  • Alcune versioni Unix / Linux incentrate sulla stabilità volte sono molto indietro con il rilascio di questi due linguaggi di scripting. Non molto tempo fa, il Perl di RHEL era al 5.8.8 - una versione di Perl di otto anni! Se qualcuno voleva usare funzionalità più moderne, dovevi installare la tua versione.
  • Programmi come Perlbrew e Pythonbrew consentono di installare più versioni di queste lingue. Dipendono dagli script che manipolano il PERCORSO per ottenere la versione desiderata. La codifica rigida del percorso significa che non posso eseguire il mio script sotto birra .
  • Non molto tempo fa (okay, è stato molto tempo fa) che Perl e Python non erano pacchetti standard inclusi nella maggior parte dei sistemi Unix. Ciò significava che non sapevi dove fossero installati questi due programmi. Era sotto /bin? /usr/bin? /opt/bin? Chissà? Usando #! /usr/bin/env perlsignificava che non dovevo saperlo.

E ora perché non dovresti usare #! /usr/bin/env bash

Quando il percorso è codificato nello shebang, devo correre con quell'interprete. Pertanto, #! /bin/bashmi costringe a utilizzare la versione installata predefinita di bash. Poiché le funzionalità di bash sono molto stabili (prova a eseguire una versione 2.x di uno script Python in Python 3.x) è molto improbabile che il mio particolare script BASH non funzioni, e poiché il mio script bash è probabilmente utilizzato da questo sistema e da altri sistemi , l'utilizzo di una versione non standard di bash può avere effetti indesiderati. È molto probabile che io voglia assicurarmi che la versione standard stabile di bash sia usata con il mio script di shell. Quindi, probabilmente voglio codificare il percorso nel mio shebang.


5
Questo non è vero: "La posizione standard di bash è / bin" (a meno che tu non possa citare un documento standard) è forse più accurata di quella che è la "solita" posizione sulla maggior parte delle distribuzioni e macos Linux, ma non è un standard sui sistemi unix in generale (e in particolare non è la posizione sulla maggior parte dei * bsds).
tesch1

13

Per invocarlo bashè un po 'eccessivo. A meno che tu non ne abbia multiplibash binari come il tuo in ~ / bin, ma ciò significa anche che il tuo codice dipende da $ PATH che contiene le cose giuste.

È utile per cose come pythonse. Esistono script e ambienti wrapper che portano all'uso di file pythonbinari alternativi .

Ma non si perde nulla usando il percorso esatto del binario finché si è sicuri che sia il binario che si desidera veramente.


Spot on per python. Ho perso il conto del numero di posti che si pythonpossono trovare 😀
zigg

2
D'accordo, /usr/bin/envè più utile per Python, specialmente se usi virtualenv.
Dennis,

10

Ci sono molti sistemi che non hanno Bash in /bin, FreeBSD e OpenBSD solo per citarne alcuni. Se la tua sceneggiatura è pensata per essere trasportabile su molti Unices diversi, potresti voler usare #!/usr/bin/env bashinvece di#!/bin/bash .

Si noti che questo non vale per sh; per gli script Bourne conformi Io esclusivamente uso #!/bin/sh, dal momento che penso che praticamente ogni Unix esistente ha sha /bin.


Nella directory Ubuntu 18.04 /bin, vedo sh -> dash. Simbolicamente collegato a dash, rivelando la natura Debian di Ubuntu. Esegui queste tre stringhe di comando per realizzare che tutto si riduce alle preferenze individuali: which bashquindi, which shquindi which dash.
noobninja,

0

Preferirei avvolgere il programma principale in uno script come di seguito per controllare tutti i bashdisponibili sul sistema. Meglio avere un maggiore controllo sulla versione che utilizza.

#! /usr/bin/env bash

# This script just chooses the appropriate bash
# installed in system and executes testcode.main

readonly DESIRED_VERSION="5"

declare all_bash_installed_on_this_system
declare bash

if [ "${BASH_VERSINFO}" -ne "${DESIRED_VERSION}" ]
then
    found=0

    all_bash_installed_on_this_system="$(\
        awk -F'/' '$NF == "bash"{print}' "/etc/shells"\
        )"

    for bash in $all_bash_installed_on_this_system
    do
        versinfo="$( $bash -c 'echo ${BASH_VERSINFO}' )"
        [ "${versinfo}" -eq "${DESIRED_VERSION}" ] && { found=1 ; break;}
    done
    if [ "${found}" -ne 1 ]
    then
        echo "${DESIRED_VERSION} not available"
        exit 1
    fi
fi

$bash main_program "$@"

0
 #!/usr/bin/env bash

è sicuramente migliore perché trova il percorso eseguibile bash dalla variabile di ambiente di sistema.

Vai alla tua shell Linux e digita

env

Stampa tutte le variabili di ambiente.

Vai allo script della shell e digita

echo $BASH

Stamperà il tuo percorso bash (secondo l'elenco delle variabili d'ambiente) che dovresti usare per costruire il tuo percorso shebang corretto nel tuo script.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.