命令行参数
在本教程中,我们将学习如何直接读取命令行参数(使用 OCaml 的 Sys.argv
数组),以及如何使用标准库的 Arg
模块更轻松地实现此操作。
Sys.argv
与 C 和许多其他语言一样,传递给给定程序的命令行参数存储在一个数组中。遵循传统,此数组命名为 argv
。它位于标准库的 Sys
模块中,因此其全名为 Sys.argv
。包括程序名称本身在内的参数数量仅仅是数组的长度。可以使用 Array.length
函数获取。
以下程序显示参数及其在 Sys.argv
中的位置
let () =
for i = 0 to Array.length Sys.argv - 1 do
Printf.printf "[%i] %s\n" i Sys.argv.(i)
done
如果将以上程序保存为 args.ml
,并运行 ocaml args.ml arg1 arg2 arg3
,则会得到以下结果
$ ocaml args.ml arg1 arg2 arg3
[0] args.ml
[1] arg1
[2] arg2
[3] arg3
请注意,ocaml
启动了一个子进程,该子进程实际上运行程序,其中 argv 为 args.ml arg1 arg2 arg3
。您还可以使用 ocamlopt -o args args.ml
编译您的程序,然后运行 ./args arg1 arg2 arg3
,您将得到以下结果
$ ocamlopt -o args args.ml
$ ./args arg1 arg2 arg3
[0] ./args
[1] arg1
[2] arg2
[3] arg3
Arg
模块
使用 OCaml 标准库有一个用于编写命令行界面的模块,因此我们不必直接使用 Sys.argv
。我们将考虑 OCaml 文档中的示例,这是一个用于追加文件的程序。
首先,我们设置在命令行格式错误或请求帮助时打印的使用信息
let usage_msg = "append [-verbose] <file1> [<file2>] ... -o <output>"
现在,我们创建一些引用来保存从命令行收集的信息。Arg
模块将在读取命令行时为我们填充这些信息。
let verbose = ref false
let input_files = ref []
let output_file = ref ""
我们有一个布尔引用用于 -verbose
标志,其默认值为 false
。然后我们有一个引用指向一个列表,该列表将保存所有输入文件的名称。最后,我们有一个字符串引用,其中将放置由 -o
指定的单个输出文件名。
我们将需要一个函数来处理匿名输入,即没有前置标志的输入。在本例中,这些是我们的输入文件名。我们的函数只是将文件名添加到前面定义的引用中。
let anon_fun filename = input_files := filename :: !input_files
最后,我们构建命令行标志规范列表。每个规范都是一个元组,包含标志名称、遇到标志时要采取的操作以及帮助字符串。
let speclist =
[
("-verbose", Arg.Set verbose, "Output debug information");
("-o", Arg.Set_string output_file, "Set output file name");
]
这里我们有两种操作:Arg.Set
操作设置布尔引用,Arg.Set_string
操作设置字符串引用。当然,我们的 input_files
引用将由已定义的 anon_fun
函数更新。
现在我们可以调用 Arg.parse
,并向其提供我们的规范列表、匿名函数和使用信息。一旦它返回,引用将填充所有必需的信息以追加我们的文件。
let () = Arg.parse speclist anon_fun usage_msg
(* Main functionality here *)
让我们将我们的程序保存为 append.ml
并使用 ocamlopt -o append append.ml
编译它并试用一下
$ ocamlopt -o append append.ml
$ ./append -verbose one.txt two.txt -o three.txt
$ ./append one.txt two.txt
$ ./append -quiet
./append: unknown option '-quiet'.
append [-verbose] <file1> [<file2>] ... -o <output>
-verbose Output debug information
-o Set output file name
-help Display this list of options
--help Display this list of options
[2]
$ ./append -help
append [-verbose] <file1> [<file2>] ... -o <output>
-verbose Output debug information
-o Set output file name
-help Display this list of options
--help Display this list of options
以下是整个程序
let usage_msg = "append [-verbose] <file1> [<file2>] ... -o <output>"
let verbose = ref false
let input_files = ref []
let output_file = ref ""
let anon_fun filename =
input_files := filename :: !input_files
let speclist =
[("-verbose", Arg.Set verbose, "Output debug information");
("-o", Arg.Set_string output_file, "Set output file name")]
let () =
Arg.parse speclist anon_fun usage_msg;
(* Main functionality here *)
Arg
模块除了 Set
和 Set_string
之外还有更多操作,以及一些用于解析更复杂命令行的底层函数。
其他解析命令行选项的工具
有一些库的功能不同于或比内置的 Arg
模块更广泛
-
Cmdliner 是一个用于命令行处理的现代界面,它还可以自动生成 UNIX 手册页。
-
Clap 是一个命令行解析器。
-
Minicli 对拒绝格式错误的命令行提供了良好的支持,而其他命令行解析器可能会默默接受。
-
Getopt for OCaml 类似于 GNU getopt。