Nie jestem pewien co do następującego skryptu ( hello.go
).
//usr/bin/env go run $0 $@ ; exit
package main
import "fmt"
func main() {
fmt.Printf("hello, world\n")
}
Można wykonać. (w MacOS X 10.9.5)
$ chmod +x hello.go
$ ./hello.go
hello, world
Od początku nie słyszałem o shebang //
. I nadal działa, gdy wstawię pustą linię na górze skryptu. Dlaczego ten skrypt działa?
//&>/dev/null;x="${0%.*}";[ ! "$x" -ot "$0" ]||(rm -f "$x";cc -o "$x" "$0")&&exec "$x" "$@"
...
///....
zamiast//...
być najbardziej kompatybilną!go run "$0" "$@"
Odpowiedzi:
To nie jest shebang, to tylko skrypt uruchamiany przez domyślną powłokę. Powłoka wykonuje pierwszą linię
co powoduje,
go
że jest wywoływana z nazwą tego pliku, więc wynik jest taki, że plik ten jest uruchamiany jako skrypt go, a następnie powłoka wychodzi bez patrzenia na resztę pliku.Ale po co zaczynać
//
zamiast sprawiedliwego/
lub właściwego seksu#!
?Wynika to z faktu, że plik musi być prawidłowym skryptem go, w przeciwnym razie go będzie narzekać. W go znaki
//
oznaczają komentarz, więc go widzi pierwszy wiersz jako komentarz i nie próbuje go interpretować. Znak ten#
jednak nie oznacza komentarza, więc normalny shebang spowodowałby błąd, gdy go interpretuje plik.Powodem tej składni jest po prostu zbudowanie pliku, który jest zarówno skryptem powłoki, jak i skryptem go, bez jednego kroku na drugim.
źródło
/
ponieważ sufiks ścieżki jest zdefiniowany jako/.
; Gdya
nie jest dowiązaniem symbolicznym,a
jest takie samo, jaka/
to, coa/.
Thera to przypadki, w których ścieżka może uzyskać dodatkowy/
bez zmiany znaczenia. Podczas wyprowadzania ścieżki kanonicznej występuje krok normalizacyjny obejmujący kolejne ukośniki jednym. To prawda, że nie jest to czysta część składni formalnej.///usr/bin/env go run $0 $@ ; exit
...Działa, ponieważ domyślnie plik wykonywalny przyjmuje się jako skrypt / bin / sh. To znaczy, jeśli nie określiłeś żadnej konkretnej powłoki - jest to #! / Bin / sh.
// jest po prostu ignorowany w ścieżkach - można uznać, że ma on wartość „single” /.
Możesz więc wziąć pod uwagę, że masz skrypt powłoki z pierwszym wierszem:
Co robi ta linia? Działa „env” z paramentami „uruchom $ 0 $ @”. tam jest polecenie „go”, a „run $ 0 $ @” to argumenty i kończy skrypt. $ 0 to nazwa skryptu. $ @ to oryginalne argumenty skryptu. Więc linia biegnie dalej, która uruchamia ten skrypt z jego argumentami
Istnieją dość interesujące szczegóły, jak wskazano w komentarzach, że dwa ukośniki są zdefiniowane w implementacji, a skrypt ten stałby się poprawny POSIX, gdyby podał trzy lub więcej ukośników. Zobacz http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html, aby uzyskać szczegółowe informacje na temat tego, w jaki sposób ukośniki powinny być obsługiwane w ścieżkach.
Zauważ też, że istnieje inny błąd w skrypcie: $ @ zamiast tego poprawne jest użycie „$ @”, ponieważ w przeciwnym razie, jeśli jakikolwiek parametr zawiera spacje, zostanie podzielony na wiele parametrów. Na przykład nie możesz przekazać nazwy pliku ze spacjami, jeśli nie używasz „$ @”
Ten konkretny skrypt oczywiście opiera się na idei, że „//” jest równe „/”
źródło
Będzie to działać w C ++ (i C, jeśli C pozwala // na komentarze)
//usr/bin/env sh -c 'p=$(expr '"_$0"' : "_\(.*\)\.[^.]*"); make $p > /dev/null && $p'; exit
źródło