命令列參數
在本教學中,我們將學習如何直接讀取命令列參數,使用 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。