Ich bin verwirrt, wenn ich dem Skript ( hello.go
) folge .
//usr/bin/env go run $0 $@ ; exit
package main
import "fmt"
func main() {
fmt.Printf("hello, world\n")
}
Es kann ausgeführt werden. (unter MacOS X 10.9.5)
$ chmod +x hello.go
$ ./hello.go
hello, world
Ich habe noch nie von Shebang gehört //
. Und es funktioniert immer noch, wenn ich oben im Skript eine leere Zeile einfüge. Warum funktioniert dieses Skript?
//&>/dev/null;x="${0%.*}";[ ! "$x" -ot "$0" ]||(rm -f "$x";cc -o "$x" "$0")&&exec "$x" "$@"
...
///....
anstatt der//...
kompatibelste zu sein!go run "$0" "$@"
Antworten:
Es ist kein Scheiß, es ist nur ein Skript, das von der Standard-Shell ausgeführt wird. Die Shell führt die erste Zeile aus
was bewirkt , dass
go
der Name dieser Datei aufgerufen werden, so das Ergebnis ist , dass diese Datei als ein Go - Skript ausgeführt wird und dann die Shell beendet , ohne den Rest der Datei zu suchen.Aber warum mit
//
statt nur/
oder einem richtigen Schafskopf anfangen#!
?Dies liegt daran, dass die Datei ein gültiges go-Skript sein muss oder go sich beschwert. In go bezeichnen die Zeichen
//
einen Kommentar. Go betrachtet die erste Zeile also als Kommentar und versucht nicht, diesen zu interpretieren. Das Zeichen gibt#
jedoch keinen Kommentar an, sodass ein normaler Shebang zu einem Fehler führen würde, wenn go die Datei interpretiert.Dieser Grund für die Syntax besteht lediglich darin, eine Datei zu erstellen, die sowohl ein Shell-Skript als auch ein Go-Skript ist, ohne dass einer auf den anderen tritt.
quelle
/
als Pfadsuffix wird definiert als/.
; Wenna
es sich nicht um einen Symlink handelt,a
ista/
dies dasselbe wie beia/.
Thera. In diesen Fällen kann ein Pfad einen zusätzlichen Pfad erhalten,/
ohne dass sich die Bedeutung ändert. Wenn ein kanonischer Pfad abgeleitet wird, wird in einem Normalisierungsschritt ein Schrägstrich in Folge zu einem Schrägstrich zusammengezogen. Zugegeben, es ist kein sauberer Teil der formalen Syntax.///usr/bin/env go run $0 $@ ; exit
...Es wird ausgeführt, weil als ausführbare Datei standardmäßig / bin / sh-Skript angenommen wird. Dh wenn Sie keine bestimmte Shell angegeben haben - es ist #! / Bin / sh.
Das // wird in Pfaden einfach ignoriert - Sie können es als einzelnes '/' betrachten.
Sie können also davon ausgehen, dass Sie ein Shell-Skript mit der ersten Zeile haben:
Was macht diese Zeile? Es läuft 'env' mit den Parametern 'go run $ 0 $ @'. Es gibt den Befehl 'go' und 'run $ 0 $ @' als Argumente und beendet das Skript anschließend. $ 0 ist dieser Skriptname. $ @ sind ursprüngliche Skriptargumente. Also läuft diese Zeile los, die dieses Skript mit seinen Argumenten ausführt
Wie in Kommentaren erwähnt, gibt es sehr interessante Details, dass zwei Schrägstriche implementierungsdefiniert sind und dieses Skript POSIX-korrekt wird, wenn drei oder mehr Schrägstriche angegeben werden. Weitere Informationen zum Umgang mit Schrägstrichen in Pfaden finden Sie unter http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html .
Beachten Sie auch, dass es einen weiteren Fehler im Skript gibt, nämlich $ @. Es ist richtig, stattdessen "$ @" zu verwenden, da andernfalls, wenn ein Parameter Leerzeichen enthält, dieser in viele Parameter aufgeteilt wird. Sie können beispielsweise keinen Dateinamen mit Leerzeichen übergeben, wenn Sie nicht das "$ @" verwenden.
Dieses spezielle Skript basiert offensichtlich auf der Idee, dass '//' gleich '/' ist.
quelle
Dies funktioniert für C ++ (und C, wenn dieses C // für Kommentare zulässt)
//usr/bin/env sh -c 'p=$(expr '"_$0"' : "_\(.*\)\.[^.]*"); make $p > /dev/null && $p'; exit
quelle