Shebang começando com '//'?

59

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

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

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

Pode executar. (no MacOS X 10.9.5)

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

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

    
por kawty 16.10.2014 / 17:08

3 respostas

70

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

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

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

Mas por que começar com // em vez de apenas / ou um bom shebang #! ?

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

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

    
por 16.10.2014 / 17:26
8

Ele é executado porque, por padrão, o arquivo executável é assumido como script / bin / sh. Ou seja se você não especificou nenhum shell em particular - é #! / bin / sh.

O // é apenas ignorado nos caminhos - você pode considerar como '/'.

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

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

O que essa linha faz? Ele roda 'env' com os paramenters 'go run $ 0 $ @'. lá 'go' é o comando e 'run $ 0 $ @' são args e sai do script depois. $ 0 é esse nome de script. $ @ são argumentos de script originais. Então, esta linha roda vai, que roda este script com seus argumentos

Existem detalhes bastante interessantes, como apontado nos comentários, que duas barras são definidas pela implementação, e esse script se tornaria POSIX-correto se ele especificasse três ou mais barras. Consulte o link para obter detalhes sobre como as barras devem ser manipuladas nos caminhos.

Note 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 você não estiver usando o "$ @"

Este script em particular, obviamente, baseia-se na ideia de que '//' é igual a '/'

    
por 16.10.2014 / 17:21
0

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

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

    
por 06.02.2018 / 01:58