您当前的位置: 首页 >> 热门资讯

开发go语言用什么ide_一次运用Go语言编写的脚本经历,越早知道越好

作者:admin 日期:2024-12-29 点击数:0

作者 | Eyal译者 | 金灵杰1 为什么 Go 语言适合编写脚本? 通常,人们认为 Python 和 Bash 是主流的脚本语言,而 C、C++ 和 Java 则不适合用于脚本编程然而,有一些语言处于这两者之间。

Go 语言的应用场景非常广泛,包括编写 Web 服务器、流程管理和系统编程接下来,我将展示 Go 语言还可以简单地用于编写脚本哪些因素使 Go 语言适合编写脚本呢?Go 语言简洁易读,且代码相对简短,这使得脚本易于维护。

Go 语言有许多稳定的、经过测试的库,能够帮助编写简洁且健壮的脚本如果我的大部分代码都是用 Go 语言编写的,那么我更倾向于使用 Go 语言作为脚本语言当代码需要多人协作维护时,使用一种大家都熟悉的语言可以降低维护成本。

2 Go 语言几乎完全支持脚本功能 实际上,我已经能够使用 Go 语言编写脚本这要归功于 Go 的 run 子命令如果脚本名为 my-script.go,我们可以通过 go run my-script.go 来运行。

在这里,需要特别关注 go run 命令Go 语言与 Bash 和 Python 不同之处在于,后者是解释型语言,它们的脚本在读取时即被执行而 Go 语言则是在用户输入 go run 后编译程序,然后执行。

由于 Go 编译速度很快,看起来就像解释执行一样尽管有人认为 go run 只是个玩具,但如果我们要编写脚本并喜欢 Go 语言,这个工具正好满足我们的需求3 那么一切都很好,对吗? 我们可以通过 go run 命令来编写和运行脚本。

但问题来了,我比较懒,希望像运行其他脚本一样,通过类似 ./my-script.go 的方式来运行脚本,而不是 go run my-script.go这里讨论的是一个简单的脚本,它与 Shell 通过两种方式交互:从命令行获取输入数据,并设置退出状态码。

这并不是 Shell 脚本中所有可能的交互方式(还有环境变量、信号、标准输入、标准输出和标准错误等),但这两个是比较复杂的这个脚本输出“Hello”和从命令行获取的第一个参数,并设置退出状态码为 42:

package main import ( "fmt" "os" ) func main() { fmt.Println("Hello", os.Args[1]) os.Exit(42) }

使用 go run 命令的结果如下: $ go run example.go world Hello world exit status 42 $ echo $? 1

稍后我们将讨论这个问题我们可以使用 go build 命令使用 go build 命令运行脚本的方法如下: $ go build $ ./example world Hello world $ echo $? 42 。

使用 go build 命令时,调试脚本的流程如下: $ vim ./example.go $ go build $ ./example.go world Hi world $ vim ./example.go $ go build $ ./example.go world Bye world

而我希望的流程是这样的: $ chmod +x example.go $ ./example.go world Hello world $ echo $? 42

对应的调试流程是: $ vim ./example.go $ ./example.go world Hi world $ vim ./example.go $ ./example.go world Bye world

这看起来很简单,对吧?4 Shebang 类 Unix 系统支持 ShebangShebang 用于告诉 Shell 使用哪种解释器来运行脚本我们可以根据所使用的脚本语言来设置 Shebang 行通常,我们会使用 env 命令作为脚本执行器,这样就无需使用解释器的绝对路径。

例如,可以设置 Shebang 为 #! /usr/bin/env python,这样 Python 解释器将运行该脚本当名称为 example.py 的脚本有上述的 Shebang 行,并且具有可执行属性(可以通过 chmod +x example.py 命令添加)时,可以在 Shell 中输入 ./example.py arg1 arg2 来运行。

此时 Shell 会读取 Shebang 行,然后开始一系列操作:Shell 开始运行 /usr/bin/env python example.py arg1 arg2实际上,这等同于 Shebang 行加上脚本名及额外的参数。

该命令执行 /usr/bin/env,参数是 /usr/bin/env python example.py arg1 arg2然后 env 命令调用 python 命令,执行 python example.py arg1 arg2。

最后,python 运行 example.py 脚本,参数是 example.py arg1 arg2现在,让我们尝试给 Go 脚本添加 Shebang第一次幼稚的尝试我们首先设置一个幼稚的 Shebang 来使用 go run 执行这个脚本。

加了 Shebang 之后的脚本如下: #! /usr/bin/env go run package main import ( "fmt" "os" ) func main() { fmt.Println("Hello", os.Args[1]) os.Exit(42) }

然后尝试运行,结果如下: $ ./example.go /usr/bin/env: ‘go run’: No such file or directory

发生了什么?Shebang 机制将 go run 整体作为一个 env 命令的参数,但实际上并不存在这个命令输入 which "go run" 也会得到类似的结果第二次尝试一个可行的方案是将 Shebang 设置为 #! /usr/local/go/bin/go run。

在我们尝试之前,就会发现一个问题:go 二进制文件在不同系统上的路径不同,写死绝对路径会导致脚本无法兼容安装在其他位置的 go另一个解决方案是使用 alias gorun="go run" 创建一个别名,之后将 Shebang 修改为 #! /usr/bin/env gorun。

【星界云手机】解放你的双手,畅玩手游新境界!云端托管手游,24小时不间断游戏体验,让你轻松练级打日常。告别手续繁琐,只需一键连接,即刻进入游戏世界,开启全新的游戏方式!

使用这种方式,我们需要在运行脚本的系统中都设置这个别名输出如下: $ ./example.go package main: example.go:1:1: illegal character U+0023 '#'

解释:从这个输出来看,我们有一个好消息,也有一个坏消息,你想先听哪个?我先说好消息吧:-)好消息是这个方案成功了,执行脚本之后 go run 命令正常调用了坏消息:井号在许多脚本语言中,Shebang 开头的井号会被当成注释忽略。

但是对 Go 语言编译器来说,开头的井号变成了“非法字符”解决方案当脚本不包含 Shebang 行时,不同的 Shell 会回退到不同的解析器Bash 会使用自己来运行脚本,而 zsh 会回退到使用 sh。

这给我们提供了一种解决方案,这也是 StackOverflow 上提到的一种解决方案由于 // 是 Go 语言中定义的注释,而我们可以使用 //usr/bin/env 来替代 /usr/bin/env(在路径分割符中,// == /),因此第一行可以设置成:

//usr/bin/env go run "$0" "$@" 结果如下: $ ./example.go world Hi world exit status 42 ./test.go: line 2: package: command not found ./test.go: line 4: syntax error near unexpected token `newline' ./test.go: line 4: `import (

解释:我们距离成功又近了一步:终于有了正确的输出但是输出中还有一些错误,同时状态码也不对让我们来看下具体发生了什么正如之前所说,Bash 没有找到任何 Shebang,因此选择使用 bash ./example.go world 的方式来运行脚本(直接使用该命令会有相同输出,你也可以试下)。

非常有趣,直接使用 Bash 来运行 Go 文件 :-) 接下来,Bash 读取脚本的第一行,然后运行该命令:/usr/bin/env go run ./example.go world之前脚本中的“0”代表第一个参数,因此实际值是我们运行的脚本文件名。

“@”表示命令行中的所有参数在这个例子中会被替换成“world”到目前为止,使用 ./example.go world,脚本使用了正确的命令行参数,并输出了正确的值输出中还有诡异的一行:“exit status 42”。

这是什么?如果我们自己尝试下命令就会了解: $ go run ./example.go world Hello world exit status 42 $ echo $? 1

这是 go run 命令通过标准错误输出的go run 命令屏蔽了状态码,然后返回了状态码 1关于这个行为的讨论,可以参见 Github issue好的,那么其他几行输出呢?这是 Bash 试图解析 Go 源码,但实际失败了。

解决方案优化这个 StackOverflow 页面建议在 Shebang 之后加上 ;exit "$?"这会告诉 Bash 解释器不要再继续执行完整的 Shebang: //usr/bin/env go run "$0" "$@"; exit "$?" 。

结果如下: $ ./test.go world Hi world exit status 42 $ echo $? 1

基本上实现了:这里实现了让 Bash 使用 go run 命令执行脚本,然后立即退出,同时设置状态码为 go run 命令执行后的状态码更进一步,可以在 Shebang 行中添加一些命令,用于移除标准错误中的“退出状态”内容,甚至解析该文本并作为整个脚本的返回码。

然而:再增加 Bash 命令意味着冗长的 Shebang 行,这与最初期望的 #! /usr/bin/env go 相比过于复杂记住这只是一种 hack 的方式,而我并不喜欢 hack毕竟我们只是想用标准的 Shebang 机制。

为什么?因为这样简单、标准、优雅这或多或少也是我想找一种更加方便的语言作为脚本语言(例如 Go)来替代 Bash 的原因5 幸运的是,我们有 gorun gorun 就是我们想要的我们只需在 Shebang 中写 #! /usr/bin/env gorun,并赋予脚本可执行权限。

仅此而已,我们可以在 Shell 中执行,获得期望的结果! $ ./example.go world Hello world $ echo $? 42

太棒了!警告:兼容性当文件包含 Shebang 之后,Go 将无法编译(和我们之前看到的一样) $ go run example.go package main: example.go:1:1: illegal character U+0023 '#' 。

这两种选择不能兼得,我们只能二选一:使用 Shebang,并通过 ./example.go 方式运行脚本或者移除 Shebang,使用 go run ./example.go 运行脚本二者不可兼得!另一个问题是,当脚本文件被放在 Go 工程中时,编译器会发现这个 go 文件。

虽然该文件并不是应用程序所需要的,也会导致编译失败一个解决方案是移除 .go 后缀,但是这样就会无法使用类似 go fmt 等工具6 最后一些想法 本文讨论了使用 Go 语言来编写脚本的重要性,同时介绍了几种方式来实现脚本运行。

这里有一些总结

解释:类型:如何运行脚本退出状态码:脚本执行后,是否设置了脚本的退出状态码可执行:脚本是否可以通过 chmod +x 设置可执行权限可编译:脚本是否可以通过 go build标准:脚本是否需要标准库之外的东西。

正如上表所示,目前没有一种完美的解决方案看上去最方便且问题最少的方式是使用 go run 命令但是在我看来,这种方式太过“复杂”,而且无法“可执行”,同时退出状态码也不正确这将会导致难以区分脚本是否正确执行。

因此,我认为 Go 语言在这个领域仍然有许多工作要做我不认为让语言支持忽略 Shebang 行会有什么问题这将会解决执行问题,但是类似这种变化可能不会被 Go 社区采纳我的同事提醒我事实上 Shebang 行对于 Javascript 同样也是非法的。

但是在 Node.js 中,他们增加了一个跳过 Shebang 函数,让 Node 脚本可以在 Shell 中直接运行(译者注:由于原文时间比较久远,在 c2b01881dcb3bf302f9d83157e719cc5240a9042 版本之后 Node.js 已经对源码进行了重构,在 702331be906fe58e0ef66c7b31c7d2aeb3af3421 版本之后,原文提及的 stripShebang 函数已经被移除。

)如果 gorun 可以作为标准工具的一部分就更棒了,其他类似的还有 gofmt 和 godoc。原文链接:https://posener.github.io/go-shebang-story/

【星界云手机】让你的游戏时光更加充实!云端托管手游,无需担心设备性能、电量损耗等问题,随时畅玩游戏。搭配挂机脚本,让你的游戏之路更加轻松、高效!

本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:631580315@qq.com

标签: