Shebang che inizia con `//`?


60

Sono confuso riguardo al seguente script ( hello.go).

//usr/bin/env go run $0 $@ ; exit

package main
import "fmt"
func main() {
    fmt.Printf("hello, world\n")
}

Può eseguire. (su MacOS X 10.9.5)

$ chmod +x hello.go
$ ./hello.go
hello, world

Non ho sentito parlare di Shebang a partire da //. E funziona ancora quando inserisco una riga vuota nella parte superiore dello script. Perché funziona questo script?


//&>/dev/null;x="${0%.*}";[ ! "$x" -ot "$0" ]||(rm -f "$x";cc -o "$x" "$0")&&exec "$x" "$@" ...
REINSTATE MONICA -Jeremy Banks,

2
seguendo i commenti di @ g-man e Jörg di seguito e in base alla risposta di Gilles ( unix.stackexchange.com/a/1919/27616 ), questo trucco dovrebbe essere usato ///....invece di //...essere il più compatibile!
Olivier Dulac,

1
Questo non gestirà correttamente gli argomenti (o la posizione in una directory) con spazi senza più virgolette:go run "$0" "$@"
Charles Duffy,

Risposte:


71

Non è uno shebang, è solo uno script che viene eseguito dalla shell predefinita. La shell esegue la prima riga

//usr/bin/env go run $0 $@ ; exit 

che provoca gol'invocazione con il nome di questo file, quindi il risultato è che questo file viene eseguito come uno script go e quindi la shell esce senza guardare il resto del file.

Ma perché iniziare //invece di un semplice /o giusto shebang #!?

Questo perché il file deve essere uno script go valido, altrimenti go si lamenterà. In go, i personaggi //indicano un commento, quindi go vede la prima riga come un commento e non tenta di interpretarlo. Il personaggio #tuttavia non denota un commento, quindi un normale shebang comporterebbe un errore quando go interpreta il file.

Questo motivo della sintassi è solo quello di creare un file che è sia uno script di shell che uno script di go senza passare da uno all'altro.



3
Funzione @HermanTorjussen - la sinossi dei percorsi è abbastanza ben definita, consentendo molte varianti utili - e con il potere arriva la complessità: /come il suffisso del percorso è definito come /.; Quando anon è un collegamento simbolico, aè lo stesso a/che è lo stesso di a/.Thera nei casi in cui un percorso può ottenere un ulteriore /senza alcun cambiamento di significato. Quando si ricava un percorso canonico, c'è una fase di normalizzazione che contrae barre consecutive a una. Certo, non è una parte pulita della sintassi formale, però.
Volker Siegel,

13
In realtà, POSIX afferma che più barre sono le stesse di una singola barra tranne quando ci sono esattamente due barre esattamente all'inizio del percorso. Come è il caso qui. In tal caso, l'interpretazione del percorso dipende dall'implementazione: "Se un percorso inizia con due caratteri <slash> successivi, il primo componente che segue i caratteri <slash> iniziali può essere interpretato in modo definito dall'implementazione, sebbene più di due caratteri <slash> iniziali devono essere trattati come un singolo carattere <slash>. "
Jörg W Mittag,

11
Quindi, per renderlo portatile si dovrebbe invece scrivere ///usr/bin/env go run $0 $@ ; exit...
Ruslan,

1
@geek la shell esce ma non prima di lanciare l'interprete go. Go sta stampando ciao mondo, non la shell.
Casey,

8

Funziona perché, per impostazione predefinita, si presuppone che il file eseguibile sia / bin / sh script. Vale a dire se non hai specificato alcuna shell particolare - è #! / Bin / sh.

// è appena ignorato nei percorsi - puoi considerarlo come '/' singolo.

Quindi puoi considerare di avere uno script di shell con la prima riga:

/usr/bin/env go run $0 $@ ; exit

Cosa fa questa linea? Funziona 'env' con i paramenters 'go run $ 0 $ @'. c'è 'go' è il comando e 'run $ 0 $ @' sono args ed esce successivamente dallo script. $ 0 è questo nome di script. $ @ sono argomenti di script originali. Quindi questa linea va avanti che esegue questo script con i suoi argomenti

Vi sono dettagli piuttosto interessanti, come sottolineato nei commenti, che due barre sono definite dall'implementazione e questo script diventerebbe POSIX corretto se specificasse tre o più barre. Fare riferimento a http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html per i dettagli su come gestire le barre nei percorsi.

Nota anche che c'è un altro errore nello script $ @ è corretto usare invece "$ @", perché altrimenti se un parametro contiene spazi verrà diviso in molti parametri. Ad esempio, non è possibile passare il nome del file con spazi se non si utilizza "$ @"

Questo particolare script ovviamente si basa sull'idea che "//" è uguale a "/"


9
"// è semplicemente ignorato nei percorsi" - Non è garantito: "Se un percorso inizia con due caratteri <slash> successivi, il primo componente che segue i caratteri <slash> iniziali può essere interpretato in modo definito dall'implementazione" ( pubs .opengroup.org / onlinepubs / 9699919799 / basedefs /… )
Jörg W Mittag,

Risposta molto interessante e aggiornata.
gena2x,

1
... AFS in particolare implementato // in modo diverso, ma non è più comune.
Charles Duffy,

0

Funzionerà con C ++ (e C se quella C consente // per i commenti)

//usr/bin/env sh -c 'p=$(expr '"_$0"' : "_\(.*\)\.[^.]*"); make $p > /dev/null && $p'; exit

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.