英文:
What's the appropriate Go shebang line?
问题
#!/usr/bin/env go
英文:
I like using shebangs to run my Perl scripts directly:
#!/usr/bin/env perl
What's the shebang for Go programs?
答案1
得分: 49
//usr/bin/go run $0 $@ ; exit
示例:
//usr/bin/go run $0 $@ ; exit
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
go将//
视为单行注释,shell忽略额外的/
更新:Go安装可能在不同的位置。下面的语法将考虑到这一点,并适用于Mac:
//$GOROOT/bin/go run $0 $@ ; exit
英文:
//usr/bin/go run $0 $@ ; exit
example:
//usr/bin/go run $0 $@ ; exit
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
go treat //
as a single line comment
and shell ignore extra /
Update: Go installation may be in a different location. The syntax below will take that into account, and works for Macs:
//$GOROOT/bin/go run $0 $@ ; exit
答案2
得分: 47
我更喜欢这个:
///usr/bin/true; exec /usr/bin/env go run "$0" "$@"
与هومن جاویدپور的答案相比,这有几个优点:
-
///usr/bin/true
同时是有效的 Go 和 shell 语法。在 Go 中它是一个注释,在 shell 中它是一个空操作命令。 -
使用
exec
替换新的 shell 进程,而不是启动一个孙子进程。因此,你的 Go 程序将成为一个直接的子进程。这更高效,对于一些高级情况(如调试和监控)也很重要。 -
正确引用参数。空格和特殊字符不会引起问题。
-
前导的
///
比仅仅使用//
更符合标准。如果只使用//
,你可能会遇到实现定义的行为。这是来自 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html 的引用:
> 如果一个路径名以两个连续的 /
字符开头,则在第一个 /
字符后的组件可能以实现定义的方式解释,尽管多于两个前导 /
字符应被视为一个单独的 /
字符。
我已经在 bash、dash、zsh 和 ksh 中测试了这个答案。
示例:
///usr/bin/true; exec /usr/bin/env go run "$0" "$@"
package main
import "fmt"
func main() {
fmt.Println("你好!")
}
英文:
I prefer this:
///usr/bin/true; exec /usr/bin/env go run "$0" "$@"
This has several advantages compared to the answer by هومن جاویدپور:
-
The
///usr/bin/true
accomplishes the feat of simultaneously being valid Go and shell syntax. In Go it is a comment. In shell, it is no-op command. -
Uses
exec
to replace the new shell process instead of launching a grandchild process. As a result, your Go program will be a direct child process. This is more efficient and it's also important for some advanced situations, such as debugging and monitoring. -
Proper quoting of arguments. Spaces and special characters won't cause problems.
-
The leading
///
is more standards compliant than just//
. If you only use//
, you run the risk of bumping into implementation-defined behaviour. Here's a quote from http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html:
> If a pathname begins with two successive /
characters, the first
> component following the leading /
characters may be interpreted
> in an implementation-defined manner, although more than two leading
> /
characters shall be treated as a single /
character.
I have tested this answer with bash, dash, zsh, and ksh.
Example:
///usr/bin/true; exec /usr/bin/env go run "$0" "$@"
package main
import "fmt"
func main() {
fmt.Println("你好!")
}
答案3
得分: 16
默认情况下没有这个功能。但是有一个名为gorun的第三方工具可以实现这个功能。https://wiki.ubuntu.com/gorun
不幸的是,编译器不支持shebang行。你不能用gorun运行的代码进行编译。
英文:
There isn't one by default. There is a third-party tool called gorun that will allow you to do it, though. https://wiki.ubuntu.com/gorun
Unfortunately the compilers don't like the shebang line. You can't compile the same code you run with gorun.
答案4
得分: 8
Go程序被编译为二进制文件;我不认为有直接从源代码运行它们的选项。
这与其他编译语言(如C++或Java)类似。一些语言(如Haskell)提供了完全编译模式和“脚本”模式,您可以使用shebang行直接从源代码运行它们。
英文:
Go programs are compiled to binaries; I don't think there is an option to run them directly from source.
This is similar to other compiled languages such as C++ or Java. Some languages (such as Haskell) offer both a fully compiled mode and a "script" mode which you can run directly from source with a shebang line.
答案5
得分: 1
在我的情况下,没有GOROOT环境变量。所以我做了这个。
//$(go env | grep -i goroot | awk -F= '{print $2}' | sed 's/\"//g')/bin/go run $0 $@ ; exit
英文:
In my case, there was no GOROOT env. So I did this.
//$(go env | grep -i goroot | awk -F= '{print $2}' | sed 's/\"//g')/bin/go run $0 $@ ; exit
答案6
得分: 0
到目前为止,将sh和gorun链接起来已经被证明是我最可移植的解决方案。
///bin/sh -c true && exec gorun "$0" "$@"
package main
import (
"fmt"
"log"
"os"
)
func main() {
fmt.Println("hello")
log.Printf("args: %v", os.Args)
// just to test exit code, would be 0x11
os.Exit(17)
}
输出:
00:~ $ chmod a+x test.go && ./test.go rawr
hello
2020/01/21 23:17:40 args: [./test.go rawr]
11:~ $
英文:
So far, chaining sh and gorun has proven to be the most portable solution for me.
///bin/sh -c true && exec gorun "$0" "$@"
package main
import (
"fmt"
"log"
"os"
)
func main() {
fmt.Println("hello")
log.Printf("args: %v", os.Args)
// just to test exit code, would be 0x11
os.Exit(17)
}
OUTPUT:
00:~ $ chmod a+x test.go && ./test.go rawr
hello
2020/01/21 23:17:40 args: [./test.go rawr]
11:~ $
答案7
得分: 0
/// 2>/dev/null; gorun "$0" "$@" ; exit $?
在我看来,这是迄今为止最好的答案组合。它使用gorun
,因此可以缓存编译步骤(大大加快脚本的速度),而且在 macOS 上也可以使用。
使用以下命令安装gorun
:
go get github.com/erning/gorun
英文:
/// 2>/dev/null; gorun "$0" "$@" ; exit $?
Seems to me the best combination of the answers thus far. It uses gorun
so it caches the compilation step (which speeds up your scripts greatly), and works on macOS, too.
Install gorun
with:
go get github.com/erning/gorun
答案8
得分: 0
///bin/sh -c true && exec /usr/bin/env go run "$0" "$@"
英文:
Reading all this messages this seems the most portable:
///bin/sh -c true && exec /usr/bin/env go run "$0" "$@"
答案9
得分: 0
如果你真的想要一个可执行文件(不是用于shell的可调用文件),并且不想要依赖gorun,一个可能的解决方案可以是这样的:
#!/bin/sh
UMASK=`umask`
umask 077
tail -n +8 "$0" > /tmp/main.tmp.$$.go
umask $UMASK
(sleep 1 && rm -f /tmp/main.tmp.$$.go) &
exec go run /tmp/main.tmp.$$.go "$@"
package main
import "fmt"
func main() {
fmt.Println("hi")
}
英文:
if really you want an executable (callable not fro shells) and not wanting to require gorun a possible solution could be something like:
#!/bin/sh
UMASK=`umask`
umask 077
tail -n +8 "$0" > /tmp/main.tmp.$$.go
umask $UMASK
(sleep 1 && rm -f /tmp/main.tmp.$$.go) &
exec go run /tmp/main.tmp.$$.go "$@"
package main
import "fmt"
func main() {
fmt.Println("hi")
}
答案10
得分: 0
我的偏好是这样的:
```bash
///usr/bin/env go run "$0" "$@"; exit
你可以在我的个人hello_world.go文件中看到这个。如果我改变主意,我会更新那个文件。
解释:
- 我使用3个斜杠,就像上面的第二个答案所说的那样,以避免实现定义的行为并更加符合规范。在bash中,多个斜杠被解释为一个斜杠,所以
///usr/bin/env
和/usr/bin/env
是一样的。而且,在Go中,双斜杠//
是一个注释。所以,现在第一行既是一个有效的Bash/shell命令,又是一个有效的Bash注释。 - 使用
/usr/bin/env go
比/usr/bin/go
更好,因为你的go
可执行文件可能不在/usr/bin/go
位置。例如,which go
显示我的位置在/usr/local/go/bin/go
。env
程序可以帮助找到正确的位置。 - 如果你的文件名是
hello_world.go
,那么直接运行./hello_world.go
将调用go run "$0" "$@"
,这将在这个可执行文件上调用go run
,将其路径作为$0
传递,并将所有其他参数作为$@
传递。 - 在最后调用
exit
确保bash在那一点退出文件,并避免尝试将你的Go代码作为shell代码运行。这就像在第一行之后将整个Go代码注释掉(至少对于你的shell来说)。
///usr/bin/env go run "$0" "$@"; exit
package main
import "fmt"
import "os"
func main() {
fmt.Println("Go: Hello World.")
os.Exit(1)
}
示例运行命令和输出:
eRCaGuy_hello_world/go$ ./hello_world.go
Go: Hello World.
exit status 1
eRCaGuy_hello_world/go$ go build -o bin/ hello_world.go && bin/hello_world
Go: Hello World.
eRCaGuy_hello_world/go$ go run hello_world.go
Go: Hello World.
exit status 1
另请参阅
- 关于C和C++的答案,请参见这里:Run C or C++ file as a script
参考资料
- 这里的其他两个答案:
- 我最早看到关于
//
和exit
部分的很好解释的地方:Shebang starting with//
?
<details>
<summary>英文:</summary>
My preference is this:
```bash
///usr/bin/env go run "$0" "$@"; exit
You can see this in my personal hello_world.go file. If I ever change my mind, I'll update that file.
Doing it this way is a bit of a mix between the main two answers right now (here and here).
Explanation:
- I use 3 slashes like the 2nd answer above says to avoid implementation-defined behavior and be more-compliant. In bash, the multiple slashes are interpreted as a single slash, so
///usr/bin/env
is the same as/usr/bin/env
. And, in Go, a double slash//
is a comment. So, now the first line is both a valid Bash/shell command and a valid Bash comment. - Using
/usr/bin/env go
is better than/usr/bin/go
because yourgo
executable may not be located at/usr/bin/go
.which go
for me shows mine is located at/usr/local/go/bin/go
, for example. Theenv
program helps find your proper location. - If your file is called
hello_world.go
, then running it directly as./hello_world.go
will callgo run "$0" "$@"
, which callsgo run
on this executable, passing in the path to it as$0
and all other arguments as$@
. - Calling
exit
at the end ensures that bash exits the file at that point and avoids trying to run your Go code as shell code. It's like commenting out the whole Go (to your shell at least) after the first line.
From hello_world.go:
///usr/bin/env go run "$0" "$@"; exit
package main
import "fmt"
import "os"
func main() {
fmt.Println("Go: Hello World.")
os.Exit(1)
}
Sample run commands, and output:
eRCaGuy_hello_world/go$ ./hello_world.go
Go: Hello World.
exit status 1
eRCaGuy_hello_world/go$ go build -o bin/ hello_world.go && bin/hello_world
Go: Hello World.
eRCaGuy_hello_world/go$ go run hello_world.go
Go: Hello World.
exit status 1
See also
- For my answer for C and C++, see here: Run C or C++ file as a script
References
- These other 2 answers here:
- Where I first saw a good explanation of the
//
andexit
parts: Shebang starting with//
?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论