合适的 Go shebang 线路是什么?

发布于 2024-12-09 02:52:55 字数 112 浏览 3 评论 0原文

我喜欢使用 shebangs 直接运行我的 Perl 脚本:

#!/usr/bin/env perl

Go 程序的 shebang 是什么?

I like using shebangs to run my Perl scripts directly:

#!/usr/bin/env perl

What's the shebang for Go programs?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

水中月 2024-12-16 02:52:55

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

示例:

//usr/bin/go run $0 $@ ; exit
package main

import "fmt"

func main() {
    fmt.Println("Hello World!")
}

// 视为单行注释
并且 shell 忽略额外的 /

更新:Go 安装可能位于不同的位置。下面的语法将考虑到这一点,并且适用于 Mac:

//$GOROOT/bin/go run $0 $@ ;退出

//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

小耗子 2024-12-16 02:52:55

我更喜欢这个:

///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("你好!")
}
转瞬即逝 2024-12-16 02:52:55

默认情况下是没有的。不过,有一个名为 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.

╰◇生如夏花灿烂 2024-12-16 02:52:55

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.

岁月蹉跎了容颜 2024-12-16 02:52:55

就我而言,没有 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
水溶 2024-12-16 02:52:55

到目前为止,事实证明,链接 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:~ $ 
迷荒 2024-12-16 02:52:55

/// 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

忘你却要生生世世 2024-12-16 02:52:55

阅读所有这些消息,这似乎是最便携的:

///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" "$@"
梦巷 2024-12-16 02:52:55

如果你真的想要一个可执行文件(不能从 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")
}
梦屿孤独相伴 2024-12-16 02:52:55

我的偏好是这样的:

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

您可以在我的个人 hello_world.go< 中看到这一点/a> 文件。如果我改变主意,我会更新该文件。

这样做是现在主要两个答案之间的混合(此处此处)。

说明:

  1. 我使用 3 个斜杠,就像上面的第二个答案所说的那样,以避免实现定义的行为并更加合规。在 bash 中,多个斜杠被解释为单个斜杠,因此 ///usr/bin/env/usr/bin/env 相同。而且,在 Go 中,双斜杠 // 是注释。因此,现在第一行既是有效的 Bash/shell 命令,又是有效的 Bash 注释。
  2. 使用 /usr/bin/env go/usr/bin/go 更好,因为您的 go 可执行文件可能不位于 /usr/bin/go。例如,which go 对我来说显示我的位置位于 /usr/local/go/bin/goenv 程序可以帮助您找到正确的位置。
  3. 如果您的文件名为 hello_world.go,那么直接以 ./hello_world.go 运行它将会调用 go run "$0" "$@",它在此可执行文件上调用 go run,将其路径作为 $0 传递,将所有其他参数作为 $@ 传递。
  4. 最后调用 exit 可确保 bash 在此时退出文件,并避免尝试将 Go 代码作为 shell 代码运行。这就像在第一行之后注释掉整个 Go(至少在你的 shell 中)。

来自 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)
}

示例运行命令和输出:

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

另请参阅

  1. 对于我对 C 和 C++ 的回答,请参阅此处:运行C 或 C++ 文件作为脚本

参考文献

  1. 这里还有其他 2 个答案:
    1. https://stackoverflow.com/a/17900932/4561887
    2. https://stackoverflow.com/a/30082862/4561887
  2. 我第一次看到 //< /code> 和 exit 部分:Shebang 以 // 开头?

My preference is this:

///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:

  1. 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.
  2. Using /usr/bin/env go is better than /usr/bin/go because your go 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. The env program helps find your proper location.
  3. If your file is called hello_world.go, then running it directly as ./hello_world.go will call go run "$0" "$@", which calls go run on this executable, passing in the path to it as $0 and all other arguments as $@.
  4. 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

  1. For my answer for C and C++, see here: Run C or C++ file as a script

References

  1. These other 2 answers here:
    1. https://stackoverflow.com/a/17900932/4561887
    2. https://stackoverflow.com/a/30082862/4561887
  2. Where I first saw a good explanation of the // and exit parts: Shebang starting with //?
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文