目录
1. 概述
CLI(Command Line Interface)实用程序是Linux下应用开发的基础。正确的编写命令行程序让应用与操作系统融为一体,通过shell或script使得应用获得最大的灵活性与开发效率。例如:
- Linux提供了cat、ls、copy等命令与操作系统交互;、
- go语言提供一组实用程序完成从编码、编译、库管理、产品发布全过程支持;
- 容器服务如docker、k8s提供了大量实用程序支撑云服务的开发、部署、监控、访问等管理任务;
- git、npm等也是大家比较熟悉的工具。
尽管操作系统与应用系统服务可视化、图形化,但在开发领域,CLI在编程、调试、运维、管理中提供了图形化程序不可替代的灵活性与效率。
2. 基础知识
几乎所有语言都提供了完善的 CLI 实用程序支持工具。以下是一些入门文档:
阅读以后你应该知道 POSIX/GNU 命令行接口的一些概念与规范。命令行程序主要涉及内容:
- 命令
- 命令行参数
- 选项:长格式、短格式
- IO:stdin、stdout、stderr、管道、重定向
- 环境变量
3. 开发实践——实现selpg
selpg
用法如下:
USAGE:
selpg -s start_page -e end_page [ -f | -l lines_per_page ] [ -d dest ] [ in_filename ]
-d, --dest string print dest
-e, --end int end page(>=start) (default -1)
-l, --len int page length (default 72)
-s, --start int start page(>1) (default -1)
-f, --type string[="f"] paging by '\f' or not (default "l")
3.1 数据结构 selpg_args
首先定义数据结构 selpg_args
,在该数据结构中,定义了与 selpg
相关的一系列参数,例如:
- 开始页(start_page)
- 结束页(end_page)
- 页长(page_len)
- 页类型(page_type)
- 输入文件名(in_filename)
- 输出位置(print_dest)
type selpg_args struct {
start_page int
end_page int
page_len int /* default value, can be overriden by "-l number" on command line */
page_type string /* 'l' for lines-delimited, 'f' for form-feed-delimited */
/* default is 'l' */
in_filename string
print_dest string
}
type sp_args selpg_args
3.2 参数处理函数 processArgs
processArgs
函数主要实现了如下功能:
- 参数解析(line 2~10)
- 验证参数合法性(line 11~18)
- 处理参数
-s
,-e
(line 20~42) - 检验输入文件是否存在(line 44~53)
func processArgs(sa * sp_args) {
flag.IntVarP(&sa.start_page, "start", "s", -1, "start page(>1)")
flag.IntVarP(&sa.end_page, "end", "e", -1, "end page(>=start)")
flag.IntVarP(&sa.page_len, "len", "l", 72, "page length")
flag.StringVarP(&sa.page_type, "type", "f", "l", "paging by '\\f' or not")
flag.Lookup("type").NoOptDefVal = "f"
flag.StringVarP(&sa.print_dest, "dest", "d", "", "print dest")
flag.Usage = usage
flag.Parse()
max_int := 1 << 32 - 1
/* check the command-line arguments for validity */
if len(os.Args) < 3 {
/* Not enough args, minimum command is "selpg -sstartpage -eend_page" */
fmt.Fprintf(os.Stderr, "\n%s: not enough arguments\n", progname)
flag.Usage()
os.Exit(1)
}
/* handle 1st arg - start page */
if os.Args[1] != "-s" {
fmt.Fprintf(os.Stderr, "\n%s: 1st arg should be -s start_page\n", progname)
flag.Usage()
os.Exit(2)
}
if sa.start_page < 1 || sa.start_page > max_int {
fmt.Fprintf(os.Stderr, "\n%s: invalid start page %d\n"