忻州信息港

当前位置:

Shell和Python常被当做Linu略

2020/10/16 来源:忻州信息港

导读

Shell 和 Python 常被当做Linux脚本使用,Go能否取代它们? 为什么考虑将 Go 作为脚本语言 Go 脚本的当前在 Cl

Shell 和 Python 常被当做Linux脚本使用,Go能否取代它们? 为什么考虑将 Go 作为脚本语言 Go 脚本的当前

在 Cloudflare 的人们都非常喜欢 Go 语言。我们在许多内部软件项目以及更大的管道中使用它。但是,我们能否进入下一个层次并将其用作我们最喜欢的操作 Linux 的脚本语言呢?

为什么考虑将 Go 作为脚本语言

简短点的回答:为什么不呢?Go 相对容易学习,不冗余并且有一个强大的生态库,这些库可以重复使用避免我们从头开始编写所有代码。它可能带来的一些其他潜在优势:为你的 Go 项目提供一个基于 Go 的构建:go build 命令主要适用于小型自包含项目。更复杂的项目通常采用构建或脚本集。为什么不用 Go 编写这些脚本呢?

易于使用的非特权包:如果你想在脚本中使用第三方库,你可以简单的使用 go get 命令来获取。而且由于拉取的代码将安装在你的 GOPATH 中,使用一些第三方库并不需要员的权限(与其他一些脚本语言不同)这在大型企业环境中尤其有用。

强类型的脚本语言:如果你在脚本中的某个地方有个小的输入错误,大多数的脚本语言都会执行到有错误的地方停止。这可能会让你的处于不一致的状态(因为有些语句的执行会改变数据的状态,从而污染了执行脚本之前的状态)使用强类型语言时,许多拼写错误可以在编译时被捕获,因此有 bug 的脚本将不会首先运行。

Go 脚本的当前状态

咋一看 Go 脚本貌似很容易实现 Unix 脚本的 shebang! ... 支持。shebang 行是脚本的第一行,以 ! 开头,并指定脚本解释器用于执行脚本例如,!/bin/bash 或 !/usr/bin/env python所以无论使用何种编程语言,都确切知道如何执行脚本。Go 已经使用 go run 命令支持 .go 文件的类似于解释器的调用,所以只需要添加适当的 shebang 行!/usr/bin/env go run到任何的 .go 文件中,设置好文件的可执行状态,就可以愉快的玩耍了。

你不能在有效的 .go 文件中创建一个 shebang 行,因为 Go 语言不知道如何处理以 开头的行。而其他语言不存在这个问题,是由于 大多数情况下是一种注释的方式,所以最后解释器会忽略掉 shebang 行,但是 Go 注释是以 // 开头的并且在调用时运行会产生如下错误:

package main:helloscript.:1: illegal character U+0023

这篇文章描述了上述问题的几种解决方法,包括使用一个自定义的包装程序 gorun 作为解释器,但是都没有提供一个理想的解决方案。你可以:必须使用非标准的 shebang 行,它以 // 开头。这在技术上甚至不是 shebang 行,而是 bash shell 如何处理可执行文本文件的方式,所以这个解决方案是 bash 特有的。另外,由于 go run 的具体行为,这一行相当复杂并且不够明显(请参阅原始文章的示例)

必须在 shebang 行中使用 gorun 自定义包装程序,这很好,但是,最终得到的 .go 文件由于非法的 字符而不能与标准 go build 命令编译。

Linux 如何执行文件

OK,看起来 shebang 的方法并没有为我们提供全面的解决方案。是否还有其他方式是我们可以使用的?让我们仔细看看 Linux 内核如何执行二进制文件。 当你尝试执行一个二进制/脚本(或任何有可执行位设置的文件)时,你的 shell 最后只会使用 Linux execve 调用,将它传递给二进制文件路径,命令行参数和 当前定义的环境变量。 内核负责正确解析文件并用文件中的代码创建一个新进程。 我们中的大多数人都知道 Linux (和许多其在前期的时候他类 Unix 操作)为其可执行文件使用 ELF 二进制格式。

从用户空间扩展受支持的二进制格式

但既然我们认为 shebang 不是 Go 脚本的最佳选择,似乎我们需要别的东西。令人惊讶的是,Linux 内核已经有了一个“其他类型的”二进制支持模块,它有一个贴切的名称 binfmt_misc。该模块允许员通过定义良好的 procfs 接口直接从用户空间动态添加对各种可执行格式的支持,并且有详细记录。

让我们按照文档并尝试为 .go 文件设置二进制格式描述。首先,该指南告诉您将特殊的 binfmt_misc 文件安装到 /proc/sys/fs/binfmt_misc。如果您使用的是基于 systemd 的相对较新的 Linux 发行版,则很可能已经为您安装了文件,因为默认情况下 system 会为此安装特殊的 mount 和 automount 单元。 要仔细检查,只需运行:

另一种方法是检查 /proc/sys/fs/binfmt_misc 中是否有文件:正确安装 binfmt_misc 文件将至少创建两个名称为 register 和 status 的特殊文件。

接下来,因为我们希望我们的 .go 脚本能够正确地将退出代码传递给操作,所以我们需要将定制的 gorun 包装器作为我们的“解释器”

从技术角度上讲,我们不需要将 gorun 移动到 /usr/local/bin 或任何其他路径,而无论如何 binfmt_misc 都需要解释器的完整路径,但可以以任意权限运行此可执行文件,因此从安全视角来看限制文件访问权限是一个好主意。

在这一点上,让我们来建一个简单的 go 脚本 helloscript.go 并验证我们可以成功“解释”它。脚本如下:

检查参数传递和错误处理是否按预期工作:

现在我们需要告诉 binfmt_misc 模块如何使用 gorun 执行 .go 文件。按照文档中的描述我们需要配置如下字符串: :golang:E:go:/usr/local/bin/gorun:OC,意思是告诉:当遇到以 .go 为扩展名的可执行文件,请使用 /usr/local/bin/gorun 解释器执行该文件。字符串末尾的 OC 标志确保脚本将根据脚本本身设置的所有者信息和权限位执行,而不是在解释器二进制文件上设置的那些位。这使 Go 脚本的执行行为与 Linux 中其他可执行文件和脚本的行为相同。

让我们注册我们新的 Go 脚本二进制格式:

如果成功注册了,则应在 /proc/sys/fs/binfmt_misc 目录下显示新的 golang 文件。 最后,我们可以在本地执行我们的 .go 文件:

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

本文相关词条概念解析:

脚本

脚本(script)是使用一种特定的描述性语言,依据一定的格式编写的可执行文件,又称作宏或批处理文件。脚本是批处理文件的延伸,是一种纯文本保存的程序,一般来说的计算机脚本程序是确定的一系列控制计算机进行运算操作动作的组合,在其中可以实现一定的逻辑分支等。

奶粉过敏症状
小孩子积食吃什么好
孩子脸色发黄
两个月的宝宝胀气怎么办
标签

友情链接