在Lua中解析命令选项

248 阅读4分钟

当你在终端输入一个命令时,通常有一些选项,也叫_开关_或_标志_,你可以用它们来修改命令的运行方式。这是由POSIX规范定义的一个有用的惯例,所以作为一个程序员,知道如何检测和解析选项是很有帮助的。

与大多数语言一样,有几种方法可以解决Lua中解析选项的问题。我最喜欢的是alt-getopt

安装

在你的代码中获得和使用alt-getopt的最简单方法是用LuaRocks安装它。对于大多数使用情况,你可能想把它安装到你的本地项目目录中。

$ mkdir local
$ luarocks --tree=local install alt-getopt
Installing https://luarocks.org/alt-getopt-0.X.Y-1.src.rock
[...]
alt-getopt 0.X.Y-1 is now installed in /tux/myproject/local (license: MIT/X11)

另外,你也可以从GitHub下载代码。

在你的Lua代码中添加一个库

假设你已经在本地安装了这个库,那么你可以定义你的Lua包路径,然后require alt-getopt包。

package.path = package.path .. ';local/share/lua/5.1/?.lua'
local alt_getopt = require("alt_getopt")

如果你已经把它安装到一个已知的系统位置,你可以省略package.path (因为Lua已经知道要寻找全系统的库。

现在你就可以在Lua中解析选项了。

Lua中的选项解析

解析选项的第一件事是定义你的应用程序可以接受的有效选项。alt_getopt库将所有的选项主要看作是短选项,也就是说,你将选项定义为单字母。你可以在以后添加长的版本。

当你定义有效选项时,你创建了一个以冒号为界的列表(:),该列表由alt-getopts提供的get_opts 函数解释。

首先,创建一些变量来表示这些选项。变量short_optoptarg 代表短选项和选项参数。这些是任意的变量名,所以你可以随便叫它们(只要是一个有效的变量名)。

long_opts 必须存在,但我发现在你决定了短选项之后再定义长选项的值是最容易的,所以现在让它空着。

local long_opts = {}
local short_opt
local optarg

在声明了这些变量后,你可以遍历用户提供的参数,检查是否有参数与你批准的有效短选项列表相匹配。

如果发现一个有效的选项,你可以使用Lua中的pairs 函数来提取该选项的值。

要创建一个本身不接受任何参数但可以_开启_或_关闭_的选项(通常称为_开关_),你要把你要定义的短选项放在冒号(: )字符的右边。

在这个例子中,我创建了一个循环来检查短选项-a ,它是一个开关。

short_opt,optarg = alt_getopt.get_opts (arg, ":a", long_opts)
local optvalues = {}
for k,v in pairs (short_opt) do
   table.insert (optvalues, "value of " .. k .. " is " .. v .. "\n")
end
table.sort (optvalues)
io.write (table.concat (optvalues))
for i = optarg,#arg do
   io.write (string.format ("ARGV [%s] = %s\n", i, arg [i]))
end

在这个示例代码的末尾,我包含了一个for-loop来遍历命令中的任何剩余参数,因为任何没有被检测到的有效选项都必须是一个参数(可能是一个文件名、URI或者你的应用程序所操作的任何东西)。

测试代码。

$ lua test.lua -a
value of a is 1

测试脚本已经成功地检测到了选项-a ,并给它赋值为1,表示它确实存在。

用一个额外的参数再试一下。

$ lua test.lua -a hello
value of a is 1
ARGV [2] = hello

带参数的选项

有些选项需要一个自己的参数。例如,你可能想让用户将你的应用程序指向一个自定义的配置文件,将一个属性设置为一种颜色,或者设置一个图形的分辨率。在alt_getopt中,接受参数的选项被放置在短选项列表中冒号(:)的左边。

short_opt,optarg = alt_getopt.get_opts (arg, "c:a", long_opts)

测试一下代码。

$ lua test.lua -a -c my.config
value of a is 1
value of c is my.config

再试一次,这次是用一个备用参数。

$ lua test.lua -a -c my.config hello
value of a is 1
value of c is my.config
ARGV [4] = hello

长选项

短选项对于高级用户来说是很好的,但它们往往不容易被记住。你可以创建一个指向短选项的长选项表,这样用户就可以在用单字母选项简写命令之前学习长选项。

local long_opts = {
   alpha = "a",
   config = "c"
}

用户现在可以在长选项和短选项之间进行选择。

$ lua test.lua --config my.config --alpha hello
value of a is 1
value of c is my.config
ARGV [4] = hello

选项解析

下面是完整的演示代码供你参考。

#!/usr/bin/env lua
package.path = package.path .. ';local/share/lua/5.1/?.lua'
local alt_getopt = require("alt_getopt")
local long_opts = {
   alpha = "a",
   config = "c"
}
local short_opt
local optarg
short_opt,optarg = alt_getopt.get_opts (arg, "c:a", long_opts)
local optvalues = {}
for k,v in pairs (short_opt) do
   table.insert (optvalues, "value of " .. k .. " is " .. v .. "\n")
end
table.sort (optvalues)
io.write (table.concat (optvalues))
for i = optarg,#arg do
   io.write (string.format ("ARGV [%s] = %s\n", i, arg [i]))
end

在项目的Git存储库中还有更多的例子。对于任何应用程序来说,包括用户的选项都是一个重要的功能,而Lua使它很容易做到。除了 alt_getopt之外,还有其他的库,但我觉得这个库使用起来很简单、很快捷。