Шебанг, начинающийся с `//`?

Шебанг, начинающийся с `//`?

Я не совсем понимаю следующий сценарий ( hello.go).

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

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

Он может быть выполнен. (на MacOS X 10.9.5)

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

Я не слышал о shebang, начинающемся с //. И он все еще работает, когда я вставляю пустую строку в начало скрипта. Почему этот скрипт работает?

решение1

Это не шебанг, это просто скрипт, который запускается оболочкой по умолчанию. Оболочка выполняет первую строку

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

что приводит к goвызову с именем этого файла, в результате чего этот файл запускается как скрипт go, а затем оболочка завершает работу, не просматривая остальную часть файла.

Но почему //бы не начать с чего /-то более серьезного #!?

Это потому, что файл должен быть допустимым скриптом go, иначе go будет жаловаться. В go символы //обозначают комментарий, поэтому go видит первую строку как комментарий и не пытается его интерпретировать. #Однако символ не обозначает комментарий, поэтому обычный shebang приведет к ошибке, когда go интерпретирует файл.

Причина использования такого синтаксиса заключается в том, чтобы создать файл, который одновременно является и скриптом оболочки, и скриптом Go, не накладывая при этом один на другой.

решение2

Он запускается, потому что по умолчанию исполняемым файлом считается скрипт /bin/sh. Т.е. если вы не указали конкретную оболочку - это #!/bin/sh.

Символ // в путях просто игнорируется — его можно рассматривать как одиночный символ '/'.

Итак, вы можете считать, что у вас есть скрипт оболочки с первой строкой:

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

Что делает эта строка? Она запускает 'env' с параметрами 'go run $0 $@'. Здесь 'go' — команда, а 'run $0 $@' — аргументы, после чего скрипт завершает работу. $0 — имя этого скрипта. $@ — исходные аргументы скрипта. Итак, эта строка запускает go, который запускает этот скрипт с его аргументами.

Есть довольно интересные детали, как указано в комментариях, что два слеша определяются реализацией, и этот скрипт станет POSIX-корректным, если в нем указать три или более слешей. См.http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.htmlдля получения подробной информации о том, как следует обрабатывать слеши в путях.

Обратите внимание, что в скрипте есть еще одна ошибка: $@ вместо этого правильно использовать "$@", потому что в противном случае, если какой-либо параметр содержит пробелы, он будет разделен на множество параметров. Например, вы не можете передать имя файла с пробелами, если вы не используете "$@"

Этот конкретный скрипт, очевидно, полагается на идею, что «//» равнозначно «/».

решение3

Это будет работать для C++ (и C, если C допускает // для комментариев)

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

Связанный контент