Shebang que comienza con `//`?


60

Estoy confundido acerca de seguir script ( hello.go).

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

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

Se puede ejecutar (en MacOS X 10.9.5)

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

No he oído hablar de shebang desde el principio //. Y todavía funciona cuando inserto una línea en blanco en la parte superior del script. ¿Por qué funciona este script?


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

2
siguiendo los comentarios de @ g-man y Jörg a continuación, y de acuerdo con la respuesta de gilles ( unix.stackexchange.com/a/1919/27616 ), este truco debería usarse en ///....lugar de //...ser el más compatible.
Olivier Dulac

1
Esto no manejará correctamente los argumentos (o la ubicación en un directorio) con espacios sin más comillas:go run "$0" "$@"
Charles Duffy

Respuestas:


71

No es un shebang, es solo un script que se ejecuta mediante el shell predeterminado. El shell ejecuta la primera línea.

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

lo que hace goque se invoque con el nombre de este archivo, por lo que el resultado es que este archivo se ejecuta como un script go y luego el shell sale sin mirar el resto del archivo.

Pero, ¿por qué comenzar en //lugar de solo /o un shebang adecuado #!?

Esto se debe a que el archivo debe ser un script go válido, o go se quejará. En ir, los caracteres //denotan un comentario, así que ve ve la primera línea como un comentario y no intenta interpretarlo. Sin #embargo, el carácter no denota un comentario, por lo que un shebang normal provocaría un error cuando go interpreta el archivo.

Esta razón para la sintaxis es solo para construir un archivo que sea a la vez un script de shell y un script go sin que uno pise el otro.



3
Función @HermanTorjussen: la sinax de las rutas está bastante bien definida, lo que permite muchas variantes útiles, y con el poder viene la complejidad: /como sufijo de ruta se define como /.; Cuando ano es un enlace simbólico, aes lo mismo a/que a/.Thera, son casos en los que una ruta puede obtener un adicional /sin ningún cambio en el significado. Cuando se deriva una ruta canónica, hay un paso de normalización que contrae barras diagonales consecutivas. Sin embargo, no es una parte limpia de la sintaxis formal.
Volker Siegel

13
En realidad, POSIX dice que múltiples barras son lo mismo que una sola barra, excepto cuando hay exactamente dos barras exactamente al comienzo de la ruta. Como es el caso aquí. En ese caso, la interpretación de la ruta depende de la implementación: "Si un nombre de ruta comienza con dos caracteres <slash> sucesivos, el primer componente que sigue a los caracteres <slash> iniciales puede interpretarse de una manera definida por la implementación, aunque más de dos caracteres <slash> iniciales se tratarán como un solo carácter <slash> ".
Jörg W Mittag

11
Entonces, para hacerlo portátil, uno debería escribir ///usr/bin/env go run $0 $@ ; exit...
Ruslan

1
@geek el shell sale pero no antes de lanzar el intérprete go. Go está imprimiendo hola mundo, no el caparazón.
casey

8

Se ejecuta porque, por defecto, se supone que el archivo ejecutable es / bin / sh script. Es decir, si no especificó ningún shell en particular, es #! / Bin / sh.

El // simplemente se ignora en las rutas; puede considerar que está en un solo '/'.

Entonces puede considerar que tiene un script de shell con la primera línea:

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

¿Qué hace esta línea? Se ejecuta 'env' con los parámetros 'go run $ 0 $ @'. allí 'go' es el comando y 'run $ 0 $ @' son argumentos y sale del script después. $ 0 es el nombre de este script. $ @ son argumentos de guiones originales. Entonces esta línea se ejecuta y ejecuta este script con sus argumentos

Hay detalles bastante interesantes, como se señala en los comentarios, que dos barras están definidas por la implementación, y esta secuencia de comandos se corregirá POSIX si especifica tres o más barras. Consulte http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html para obtener detalles sobre cómo se deben manejar las barras en las rutas.

Tenga en cuenta también que hay otro error en el script: $ @ es correcto usar "$ @" en su lugar, porque de lo contrario, si algún parámetro contiene espacios, se dividirá en muchos parámetros. Por ejemplo, no puede pasar el nombre del archivo con espacios si no está usando "$ @"

Este script en particular obviamente se basa en la idea de que '//' es igual a '/'


99
"El // simplemente se ignora en las rutas" - Eso no está garantizado: "Si un nombre de ruta comienza con dos caracteres <slash> sucesivos, el primer componente que sigue a los caracteres <slash> iniciales se puede interpretar de una manera definida por la implementación" ( pubs .opengroup.org / onlinepubs / 9699919799 / basedefs / ... )
Jörg W Mittag

Muy interesante, respuesta actualizada.
gena2x

1
... AFS en particular implementado // de manera diferente, pero ya no es común.
Charles Duffy

0

Esto funcionará para C ++ (y C si ese C permite // para comentarios)

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.