Shebang começando com `//`?

Shebang começando com `//`?

Estou confuso sobre seguir o script ( hello.go).

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

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

Ele pode ser executado. (no MacOS X 10.9.5)

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

Eu não ouvi falar de shebang começando com //. E ainda funciona quando insiro uma linha em branco no topo do script. Por que esse script funciona?

Responder1

Não é uma coisa simples, é apenas um script que é executado pelo shell padrão. O shell executa a primeira linha

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

o que faz com goque seja invocado com o nome deste arquivo, então o resultado é que este arquivo é executado como um script go e então o shell sai sem olhar o resto do arquivo.

Mas por que começar com, //em vez de apenas /ou com uma coisa adequada #!?

Isso ocorre porque o arquivo precisa ser um script go válido, ou o go reclamará. Em go, os caracteres //denotam um comentário, então go vê a primeira linha como um comentário e não tenta interpretá-la. O caractere #, entretanto, não denota um comentário, portanto, um shebang normal resultaria em um erro ao interpretar o arquivo.

Esse motivo para a sintaxe é apenas construir um arquivo que seja um script shell e um script go, sem que um pise no outro.

Responder2

Ele é executado porque, por padrão, o arquivo executável é considerado o script /bin/sh. Ou seja, se você não especificou nenhum shell específico - é #!/bin/sh.

O // é simplesmente ignorado nos caminhos - você pode considerar que é um único '/'.

Então você pode considerar que possui um script de shell com a primeira linha:

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

O que essa linha faz? Ele executa 'env' com parâmetros 'go run $0 $@'. lá 'go' é o comando e 'run $0 $@' são argumentos e sai do script depois. $0 é o nome deste script. $@ são argumentos originais do script. Então esta linha é executada go, que executa este script com seus argumentos

Há detalhes bastante interessantes, conforme apontado nos comentários, de que duas barras são definidas pela implementação, e esse script se tornaria correto para POSIX se especificasse três ou mais barras. Referir-sehttp://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.htmlpara obter detalhes sobre como as barras devem ser tratadas nos caminhos.

Observe também que há outro erro no script $@, é correto usar "$@", caso contrário, se algum parâmetro contiver espaços, ele será dividido em vários parâmetros. Por exemplo você não pode passar o nome do arquivo com espaços se não estiver usando o "$@"

Este script em particular obviamente depende da ideia de que '//' é igual a '/'

Responder3

Isso funcionará para C++ (e C se esse C permitir // comentários)

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

informação relacionada