`//` ile başlayan Shebang?


60

Aşağıdaki script ( hello.go) hakkında kafam karıştı .

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

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

Yürütebilir. (MacOS X 10.9.5’de)

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

Onunla başlayan Shebang'ı hiç duymadım //. Ve betiğin en üstüne boş bir satır eklerken hala çalışıyor. Bu senaryo neden çalışıyor?


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

2
Aşağıdaki @ g-man ve Jörg yorumlarının ardından ve gilles cevabına göre ( unix.stackexchange.com/a/1919/27616 ), bu numara en uyumlu olmak ///....yerine kullanmalı //...!
Olivier Dulac

1
Bu, daha fazla alıntı içermeyen boşluklarla bağımsız değişkenleri (veya bir dizindeki konumu) doğru şekilde ele almaz:go run "$0" "$@"
Charles Duffy

Yanıtlar:


71

Bu bir shebang değil, sadece varsayılan kabuk tarafından çalıştırılan bir betik. Kabuk ilk satırı yürütür

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

gobu dosyanın adıyla çağrılmaya neden olur , bu nedenle sonuç bu dosyanın bir go betiği olarak çalıştırılması ve daha sonra kabuk dosyanın sonuna bakmadan çıkmasıdır.

Ama neden //sadece /veya uygun bir shebang yerine başlamakla #!?

Bunun nedeni, dosyanın geçerli bir go betiği olması gerekmesidir, veya go şikayetçi olacaktır. Go, karakterler //bir yorumu gösterir, bu yüzden go ilk satırı bir yorum olarak görür ve yorumlamaya çalışmaz. #Bununla birlikte karakter , bir yorumu göstermez, bu nedenle normal bir shebang, git dosyayı yorumlarken hataya neden olur.

Sözdiziminin bu nedeni, yalnızca bir diğerine basmadan hem kabuk hem de go komut dosyası olan bir dosya oluşturmaktır.


10
Kabuk tarafından değil çekirdek tarafından ele alınır; Gilles'in Linux'a çoklu yol ayırıcıları nasıl kullandığı konusundaki cevabına bakınız (/ home //// kullaniciadi /// dosya) .
G-Man

3
@HermanTorjussen Özelliği - yolların synax'ları oldukça iyi tanımlanmıştır, birçok faydalı değişkene izin verir - ve güçle birlikte karmaşıklık gelir: /yol eki olarak tanımlandığı gibi /.; Ne zaman abir sembolik değil, aaynı a/aynı olan a/.Thera bir yol ilave alabilirsiniz durumlardır /anlam hiçbir değişiklik olmadan. Bir kanonik yol türetilirken, ardışık eğik çizgileri birine daraltan normalizasyon aşaması vardır. Yine de, resmi sözdiziminin temiz bir parçası değil.
Volker Siegel

13
Aslında, POSIX , yolun tam başlangıcında tam olarak iki eğik çizgi olması dışında , birden fazla eğik çizginin tek bir eğik çizgiyle aynı olduğunu söylüyor . Burada olduğu gibi. Bu durumda, yolun yorumlanması uygulamaya bağlıdır: "Bir yol adı art arda iki <slash> karakteriyle başlıyorsa, baştaki <slash> karakterlerini izleyen ilk bileşen, uygulama tanımlı bir şekilde yorumlanabilir. önde gelen iki <slash> karakteri, tek bir <slash> karakteri olarak kabul edilir. "
Jörg W Mittag

11
Yani, taşınabilir yapmak için bir yerine yazmak gerekir ///usr/bin/env go run $0 $@ ; exit...
Ruslan

1
@geek kabuk çıkar ama go tercümanı başlatmadan önce çıkar. Go merhaba dünyasını basıyor, kabuğu değil.
casey

8

Çalıştırır, çünkü varsayılan çalıştırılabilir dosyanın / bin / sh script olduğu varsayılır. Yani, belirli bir kabuk belirtmediyseniz - bu #! / Bin / sh şeklindedir.

// sadece yollarda yoksayılır - tek olarak '/' olarak düşünebilirsiniz.

Böylece ilk satırda kabuk betiğiniz olduğunu düşünebilirsiniz:

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

Bu hat ne işe yarıyor? Paramenter ile 'env' çalışır 'git 0 $ @'. orada 'go' komutu ve '$ 0 $ @' run args ve daha sonra betiğinden çıkar. $ 0 bu betiğin adı. $ @, orijinal script argümanlarıdır. Yani bu satır gider, bu betiği kendi argümanları ile çalıştırır.

Yorumlarda da belirtildiği gibi, iki eğik çizginin uygulama tarafından tanımlandığını ve üç ya da daha fazla eğik çizgi belirtirse, bu komut dosyası POSIX için doğru olur. Eğik çizgilerin yollarda nasıl işlenmesi gerektiği hakkında ayrıntılı bilgi için http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html adresine bakın .

Ayrıca, $ @ betiğinde başka bir hata olduğunu unutmayın; bunun yerine "$ @" kullanmak doğrudur, aksi halde herhangi bir parametre boşluk içeriyorsa birçok parametreye bölünür. Örneğin, "$ @" kullanmıyorsanız dosya adını boşluklarla geçiremezsiniz.

Bu özel senaryo açıkça '//' nin '/' değerine eşit olduğu fikrine dayanıyor.


9
"// // sadece yollarda yoksayılır" - Bu garanti edilemez: "Bir yol adı ardışık iki <slash> karakteriyle başlıyorsa, baştaki <slash> karakterlerini izleyen ilk bileşen uygulama tarafından tanımlanmış bir şekilde yorumlanabilir" ( pubs .opengroup.org / onlinepubs / 9699919799 / basedefs /… )
Jörg W Mittag

Çok ilginç, güncellenmiş bir cevap.
gena2x

1
... özellikle AFS // farklı şekilde uygulandı, ancak artık yaygın değil.
Charles Duffy

0

Bu, C ++ için çalışacaktır (ve eğer C yorum yapabiliyorsa //)

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.