Shebang bắt đầu bằng `//`?


60

Tôi bối rối về việc theo dõi tập lệnh ( hello.go).

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

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

Nó có thể thực thi. (trên MacOS X 10.9.5)

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

Tôi chưa từng nghe về shebang //. Và nó vẫn hoạt động khi tôi chèn một dòng trống ở đầu tập lệnh. Tại sao kịch bản này hoạt động?


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

2
theo dõi các bình luận của @ g-man và Jörg bên dưới và theo câu trả lời của gilles ( unix.stackexchange.com/a/1919/27616 ), thủ thuật này nên sử dụng ///....thay vì //...tương thích nhất!
Olivier Dulac

1
Điều này sẽ không xử lý chính xác các đối số (hoặc vị trí trong một thư mục) với khoảng trắng mà không có thêm dấu ngoặc kép:go run "$0" "$@"
Charles Duffy

Câu trả lời:


71

Nó không phải là một shebang, nó chỉ là một tập lệnh được chạy bởi shell mặc định. Shell thực hiện dòng đầu tiên

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

Điều này gây ra gođược gọi với tên của tệp này, do đó, kết quả là tệp này được chạy dưới dạng tập lệnh go và sau đó trình bao thoát ra mà không nhìn vào phần còn lại của tệp.

Nhưng tại sao bắt đầu với //thay vì chỉ /hoặc một shebang thích hợp #!?

Điều này là do các tập tin cần phải là một kịch bản đi hợp lệ, hoặc đi sẽ khiếu nại. Trong khi đi, các ký tự //biểu thị một nhận xét, vì vậy go xem dòng đầu tiên là một nhận xét và không cố gắng giải thích nó. #Tuy nhiên, ký tự không biểu thị một nhận xét, vì vậy một shebang bình thường sẽ dẫn đến lỗi khi đi diễn giải tệp.

Lý do cho cú pháp này chỉ là để xây dựng một tệp vừa là tập lệnh shell vừa là tập lệnh go mà không cần bước này đến tập lệnh khác.


10
Nó được xử lý bởi kernel, không phải shell; xem câu trả lời của Gilles về cách Linux xử lý nhiều dấu tách đường dẫn (tập tin / home //// tên người dùng ///) .
G-Man

3
@HermanTorjussen Tính năng - sự đồng bộ của các đường dẫn được xác định khá rõ, cho phép rất nhiều biến thể hữu ích - và với sức mạnh đi kèm phức tạp: /vì hậu tố đường dẫn được định nghĩa là /.; Khi akhông phải là một liên kết tượng trưng, acũng giống như a/là giống như a/.Thera là trường hợp một con đường có thể nhận được thêm /không có sự thay đổi trong ý nghĩa. Khi tạo ra một đường dẫn chính tắc, có một bước chuẩn hóa hợp đồng chém liên tiếp vào một. Cấp, mặc dù nó không phải là một phần rõ ràng của cú pháp chính thức.
Volker Siegel

13
Trên thực tế, POSIX nói rằng nhiều dấu gạch chéo giống như một dấu gạch chéo trừ khi có chính xác hai dấu gạch chéo ở đầu đường dẫn. Như trường hợp ở đây. Trong trường hợp đó, việc giải thích đường dẫn phụ thuộc vào triển khai: "Nếu tên đường dẫn bắt đầu bằng hai ký tự <slash> liên tiếp, thành phần đầu tiên theo sau các ký tự <slash> có thể được hiểu theo cách được xác định theo cách thực hiện, mặc dù nhiều hơn hai ký tự <slash> hàng đầu sẽ được coi là một ký tự <slash>. "
Jörg W Mittag

11
Vì vậy, để làm cho nó di động, người ta nên viết ///usr/bin/env go run $0 $@ ; exit...
Ruslan

1
@geek shell thoát nhưng không phải trước khi khởi chạy trình thông dịch go. Đi là in thế giới xin chào, không phải vỏ.
casey

8

Nó chạy bởi vì theo mặc định, tệp thực thi được coi là tập lệnh / bin / sh. Tức là nếu bạn không chỉ định bất kỳ shell cụ thể nào - đó là #! / Bin / sh.

// chỉ bị bỏ qua trong các đường dẫn - bạn có thể xem là ở dạng đơn '/'.

Vì vậy, bạn có thể xem xét rằng bạn có kịch bản shell với dòng đầu tiên:

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

Dòng này làm gì? Nó chạy 'env' với các thông số viên 'chạy $ 0 $ @'. có 'go' là lệnh và 'chạy $ 0 $ @' là các đối số và thoát khỏi tập lệnh sau đó. $ 0 là tên tập lệnh này. $ @ là các đối số kịch bản gốc. Vì vậy, dòng này chạy đi mà chạy tập lệnh này với các đối số của nó

Có nhiều chi tiết khá thú vị, như được nêu trong các bình luận, rằng hai dấu gạch chéo được xác định theo cách triển khai và tập lệnh này sẽ trở thành POSIX chính xác nếu nó chỉ định ba dấu gạch chéo trở lên. Tham khảo http://pub.opengroup.org/onlinepub/9699919799/basingefs/V1_chap04.html để biết chi tiết về cách xử lý dấu gạch chéo trong đường dẫn.

Cũng lưu ý rằng có một lỗi khác trong tập lệnh $ @ thay vào đó là sử dụng "$ @", vì nếu không, nếu có bất kỳ tham số nào chứa khoảng trắng, nó sẽ được chia thành nhiều tham số. Ví dụ: bạn không thể chuyển tên tệp có dấu cách nếu bạn không sử dụng "$ @"

Kịch bản cụ thể này rõ ràng dựa vào ý tưởng rằng '//' bằng với '/'


9
"// chỉ bị bỏ qua trong các đường dẫn" - Điều đó không được đảm bảo: "Nếu tên đường dẫn bắt đầu bằng hai ký tự <slash> liên tiếp, thành phần đầu tiên theo sau các ký tự <slash> hàng đầu có thể được hiểu theo cách được xác định theo cách thực hiện" ( pubs .opengroup.org / onlinepubs / 9699919799 / basedefs / ... )
Jörg W Mittag

Rất thú vị, cập nhật câu trả lời.
gena2x

1
... AFS nói riêng được triển khai // khác nhau, nhưng nó không còn phổ biến nữa.
Charles Duffy

0

Điều này sẽ hoạt động cho C ++ (và C nếu C cho phép // cho ý kiến)

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.