我对以下脚本感到困惑(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
它不是一个 shebang,它只是一个由默认 shell 运行的脚本。 shell执行第一行
//usr/bin/env go run $0 $@ ; exit
这会导致go
使用该文件的名称进行调用,因此结果是该文件作为 go 脚本运行,然后 shell 退出而不查看文件的其余部分。
//
但为什么要从 just/
或适当的 shebang开始呢#!
?
这是因为该文件需要是有效的 go 脚本,否则 go 会抱怨。在 go 中,这些字符//
表示注释,因此 go 将第一行视为注释,并且不会尝试解释它。然而,该字符#
并不表示注释,因此当 go 解释文件时,普通的 shebang 会导致错误。
这种语法的原因只是为了构建一个既是 shell 脚本又是 go 脚本的文件,而不需要互相踩踏。
答案2
它运行是因为默认情况下可执行文件被假定为 /bin/sh 脚本。即,如果您没有指定任何特定的 shell - 它就是#!/bin/sh。
// 在路径中被忽略 - 您可以将其视为单个“/”。
所以你可以认为你有第一行的 shell 脚本:
/usr/bin/env go run $0 $@ ; exit
这条线有什么作用?它使用参数“go run $0 $@”运行“env”。其中“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