clingon 是一个 Common Lisp 的命令行选项的解析器,它可以轻松地解析具有复杂格式的命令行选项。例如,下面的代码可以打印给定次数的打招呼信息
#|-*- mode:lisp -*-|#
#|
exec ros -Q — $0 “$@”
|#
(progn ;;init forms
(ros:ensure-asdf)
#+quicklisp(ql:quickload ‘(clingon) :silent t)
)
(defpackage :ros.script.hello.3868869124
(:use :cl
:clingon))
(in-package :ros.script.hello.3868869124)
(defun top-level/handler (cmd)
(check-type cmd clingon:command)
(let ((count (clingon:getopt cmd :count))
(name (first (clingon:command-arguments cmd))))
(dotimes (_ count)
(declare (ignorable _))
(format t “Hello ~A!~%” name))))
(defun main (&rest argv)
(let ((app (clingon:make-command
:handler #’top-level/handler
:name “hello”
:options (list
(clingon:make-option
:integer
:description “number of greetings”
:initial-value 1
:key :count
:long-name “count”)))))
(clingon:run app argv)))
;;; vim: set ft=lisp lisp:
稍微做一些解释。首先执行命令生成上面的代码的雏形——加载依赖、包定义,以及空的函数。为了加载 clingon,将其作为函数的参数。然后分别定义一个、,以及。
在 clingon 中,类的实例对象表示一个可以在 shell 中被触发的命令,它们由函数创建。每一个命令起码要有三个要素:
,负责使用命令行选项、实现业务逻辑的函数;,命令的名字,一般会被展示在命令的用法说明中;,该命令所接受的选项。
此处的就是函数,它会被函数调用(依赖注入的味道),并将一个合适的对象传入。目前只承载了一个选项的定义,即
:integer
:description “number of greetings”
:initial-value 1
:key :count
:long-name “count”)
它定义了一个值为整数的选项,在命令行中通过指定。如果没有传入该选项,那么在使用函数取值时,会获得默认值 1。如果要从一个命令对象中取出这个选项的值,需要以它的参数的值作为参数来调用函数,正如上面的函数所示。
clingon 也可以实现诸如、这样的子命令特性。像、这样的子命令,对于 clingon 而言仍然是类的实例对象,只不过它们不会传递给函数调度,而是传递给函数的参数,如下列代码所示
(declare (ignorable cmd)))
(defun main (&rest argv)
(let ((app (clingon:make-command
:handler #’top-level/handler
:name “cli”
:sub-commands (list
(clingon:make-command
:handler #'(lambda (cmd)
(declare (ignorable cmd))
(format t “Dropped the database~%”))
:name “dropdb”)
(clingon:make-command
:handler #'(lambda (cmd)
(declare (ignorable cmd))
(format t “Initialized the database~%”))
:name “initdb”)))))
(clingon:run app argv)))
在 clingon 中通过命令行传递给进程的信息分为选项和参数两种形态,选项是通过名字来引用,而参数则通过它们的下标来引用。
例如在第一个例子中,就定义了一个名为的选项,它在解析结果中被赋予了这个关键字,可以通过函数来引用它的值;
与之相反,变量是从命令行中解析了选项后、剩余的参数中的第一个,它是以位置来标识的。clingon 通过函数来定义选项,它提供了丰富的控制能力。
选项有好几种名字,一种叫做,是在程序内部使用的名字,用作函数的参数之一;
一种叫做,一般为多于一个字符的字符串,如,在命令行该名称需要带上两个连字符的前缀来使用,如;
最后一种叫做,为一个单独的字符,如,在命令行中带上一个连字符前缀来使用,如。
通过传入参数给函数,可以要求一个选项为必传的。
例如下面的命令的选项就是必传的
(dotimes (i (clingon:getopt cmd :n))
(declare (ignorable i))
(format t “.”)))
(defun main (&rest argv)
(let ((app (clingon:make-command
:handler #’top-level/handler
:name “dots”
:options (list
(clingon:make-option
:integer
:description “打印的英文句号的数量”
:key :n
:long-name “n”
:required t)))))
(clingon:run app argv)))
如果不希望在一些最简单的情况下也要繁琐地编写这样的命令行参数,可以用来指定。除此之外,也可以让选项默认读取指定的环境变量中的值,使用指定环境变量名即可
(format t “Hello ~A~%” (clingon:getopt cmd :username)))
(defun main (&rest argv)
(let ((app (clingon:make-command
:handler #’top-level/handler
:name “greet”
:options (list
(clingon:make-option
:string
:description “用户名”
:env-vars ‘(“GREETER_USERNAME”)
:key :username
:long-name “username”)))))
(clingon:run app argv)))
像中的选项就是可以多次使用的,每指定一次就可以在请求中添加一个 HTTP 头部,如下图所示
在 clingon 中可以通过往函数传入来实现。当用取出类型为的选项的值时,得到的是一个列表,其中依次存放着输入的值的字符串。
(let ((messages (clingon:getopt cmd :message)))
(format t “~{~A~^~%~}” messages)))
(defun main (&rest argv)
(let ((app (clingon:make-command
:handler #’top-level/handler
:name “commit”
:options (list
(clingon:make-option
:list
:description “提交的消息”
:key :message
:long-name “message”
:short-name #\m)))))
(clingon:run app argv)))
另一种情况是尽管没有值,但仍然多次使用同一个选项。例如命令的选项,使用的次数越多(最多为 3 次),则打印的调试信息也就越详细。这种类型的选项在 clingon 中称为。
(format t “Verbosity: ~D~%” (clingon:getopt cmd :verbose)))
(defun main (&rest argv)
(let ((app (clingon:make-command
:handler #’top-level/handler
:name “log”
:options (list
(clingon:make-option
:counter
:description “啰嗦程度”
:key :verbose
:long-name “verbose”
:short-name #\v)))))
(clingon:run app argv)))
有一些选项只需要区分【有】和【没有】两种情况就可以了,而不需要在意这个选项的值——或者这类选项本身就不允许有值,例如命令的选项和。
这种选项的类型为,如果指定了这个选项,那么取出来的值始终为。与之相反,类型取出来的值始终为。
(let ((rv (software-type)))
(when (clingon:getopt cmd :shout)
(setf rv (concatenate ‘string (string-upcase rv) “!!!!111”)))
(format t “~A~%” rv)))
(defun main (&rest argv)
(let ((app (clingon:make-command
:handler #’top-level/handler
:name “info”
:options (list
(clingon:make-option
:boolean/true
:description “大喊”
:key :shout
:long-name “shout”)))))
(clingon:run app argv)))
如果一个选项尽管接受的是字符串,但并非所有输入都是有意义的,例如命令的选项。从的 man 文档可以看到,它所支持的图片类型是有限的,如、、等。
比起声明一个类型的选项,让 clingon 代劳输入值的有效性检查来得更轻松,这里可以使用类型
(format t “~A~%” (clingon:getopt cmd :hash-type)))
(defun main (&rest argv)
(let ((app (clingon:make-command
:handler #’top-level/handler
:name “digest”
:options (list
(clingon:make-option
:choice
:description “哈希类型”
:items ‘(“MD5” “SHA1”)
:key :hash-type
:long-name “hash-type”)))))
(clingon:run app argv)))
以上就是CommonLisp中解析命令行参数示例的详细内容,更多关于CommonLisp命令行参数的资料请关注脚本之家其它相关文章!