Shebang, der mit `//` beginnt?

Shebang, der mit `//` beginnt?

Ich bin verwirrt über das folgende Skript ( hello.go).

//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 gehört, dass Shebang mit beginnt //. Und es funktioniert trotzdem, wenn ich oben im Skript eine leere Zeile einfüge. Warum funktioniert dieses Skript?

Antwort1

Es ist kein Shebang, sondern nur ein Skript, das von der Standard-Shell ausgeführt wird. Die Shell führt die erste Zeile aus

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

Dies führt dazu, godass es mit dem Namen dieser Datei aufgerufen wird. Das Ergebnis ist also, dass diese Datei als Go-Skript ausgeführt wird und die Shell dann beendet wird, ohne den Rest der Datei anzusehen.

Aber warum mit beginnen, //anstatt einfach mit /oder einem richtigen Kram #!?

Dies liegt daran, dass die Datei ein gültiges Go-Skript sein muss, sonst beschwert sich Go. In Go //kennzeichnen die Zeichen einen Kommentar, sodass Go die erste Zeile als Kommentar betrachtet und nicht versucht, sie zu interpretieren. Das Zeichen #kennzeichnet jedoch keinen Kommentar, sodass ein normales Shebang zu einem Fehler führen würde, wenn Go die Datei interpretiert.

Der 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 das eine das andere beeinträchtigt.

Antwort2

Es wird ausgeführt, weil standardmäßig davon ausgegangen wird, dass es sich bei der ausführbaren Datei um das Skript /bin/sh handelt. Wenn Sie also keine bestimmte Shell angegeben haben, ist es #!/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:

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

Was macht diese Zeile? Sie führt „env“ mit den Parametern „go run $0 $@“ aus. Dabei ist „go“ ein Befehl und „run $0 $@“ sind Argumente und beendet anschließend das Skript. $0 ist der Name dieses Skripts. $@ sind die ursprünglichen Skriptargumente. Diese Zeile führt also „go“ aus, das dieses Skript mit seinen Argumenten ausführt.

Es gibt recht interessante Details, wie in Kommentaren erwähnt wird, nämlich dass zwei Schrägstriche implementierungsdefiniert sind und dieses Skript POSIX-korrekt wäre, wenn es drei oder mehr Schrägstriche angeben würde. Siehehttp://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.htmlfür Details zum Umgang mit Schrägstrichen in Pfaden.

Beachten Sie auch, dass das Skript einen weiteren Fehler enthält: $@. Es ist richtig, stattdessen "$@" zu verwenden, da sonst jeder Parameter, der Leerzeichen enthält, auf mehrere Parameter aufgeteilt wird. Sie können beispielsweise keinen Dateinamen mit Leerzeichen übergeben, wenn Sie "$@" nicht verwenden.

Dieses spezielle Skript basiert offensichtlich auf der Idee, dass „//“ gleich „/“ ist.

Antwort3

Dies funktioniert für C++ (und C, wenn dieses // für Kommentare zulässt)

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

verwandte Informationen