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 sobre shebang começando com //
. E ainda funciona quando insiro uma linha em branco na parte superior do script. Por que esse script funciona?
//&>/dev/null;x="${0%.*}";[ ! "$x" -ot "$0" ]||(rm -f "$x";cc -o "$x" "$0")&&exec "$x" "$@"
...
///....
vez de//...
ser o mais compatível!go run "$0" "$@"
Respostas:
Não é um shebang, é apenas um script que é executado pelo shell padrão. O shell executa a primeira linha
que faz
go
com que seja chamado com o nome desse arquivo, portanto, o resultado é que esse arquivo é executado como um script go e, em seguida, o shell sai sem olhar para o restante do arquivo.Mas por que começar em
//
vez de apenas/
ou de uma boa transa#!
?Isso ocorre porque o arquivo precisa ser um script go válido ou o go vai reclamar. Em movimento, os caracteres
//
denotam um comentário; portanto, ele vê a primeira linha como um comentário e não tenta interpretá-lo. O caractere#
, no entanto, não indica um comentário; portanto, um shebang normal resultaria em um erro quando o interpretar fosse o arquivo.Esse motivo para a sintaxe é apenas para criar um arquivo que seja um script de shell e um script de ir sem que um pisar no outro.
fonte
/
como o sufixo do caminho é definido/.
; Quandoa
não é um link simbólico,a
é o mesmoa/
quea/.
Thera. São casos em que um caminho pode obter um adicional/
sem alteração de significado. Ao derivar um caminho canônico, há uma etapa de normalização contratando barras consecutivas para um. É verdade que não é uma parte limpa da sintaxe formal.///usr/bin/env go run $0 $@ ; exit
...Ele é executado porque, por padrão, o arquivo executável é considerado como / bin / sh script. Ou seja, se você não especificou nenhum shell em particular - é #! / Bin / sh.
O // é apenas ignorado nos caminhos - você pode considerar que está no único '/'.
Portanto, você pode considerar que possui um shell script com a primeira linha:
O que essa linha faz? Ele roda 'env' com os parâmetros 'go run $ 0 $ @'. lá 'go' é o comando e 'run $ 0 $ @' são argumentos e sai do script posteriormente. $ 0 é esse nome de script. $ @ são argumentos de script originais. Portanto, esta linha é executada e executa esse script com seus argumentos
Existem detalhes bastante interessantes, como apontado nos comentários, de que duas barras são definidas pela implementação e esse script se tornaria POSIX correto se especificar três ou mais barras. Consulte http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html para obter detalhes sobre como as barras devem ser tratadas nos caminhos.
Observe também que há outro erro no script: $ @ é correto usar "$ @", porque, caso contrário, se algum parâmetro contiver espaços, ele será dividido em muitos parâmetros. Por exemplo, você não pode passar o nome do arquivo com espaços se não estiver usando o "$ @"
Esse script em particular obviamente depende da ideia de que '//' é igual a '/'
fonte
Isso funcionará para C ++ (e C, se esse C permitir // para comentários)
//usr/bin/env sh -c 'p=$(expr '"_$0"' : "_\(.*\)\.[^.]*"); make $p > /dev/null && $p'; exit
fonte