Selpg
Selpg 是实用的命令行程序,它可以读取终端输入或文件输入,然后根据给定参数,打印输入的指定位置。这是最初开发者的教学链接
不得不说,和别人的差距是很明显的。无论是编程规范,还是博客水准。在这里就不介绍命令行程序的规范和准则了,最初开发者的博客已经非常详细了。本文为指导博客,讲解阅读源代码和开发过程。强烈建议在阅读下文前,理解原作者的博客。
规范约定
首先,我们需要约定重新开发的 Selpg 的使用规范。
输入输出
和原来一样,我们支持以下的规则:
- 终端输入
- 重定向输入
- 终端输出
- 指定输出
参数选项
- 必选参数
我们必须指明开始页和终止页 - 可选参数
- 分页模式
–l x,指定一页为 x 行
–f,使用换页符标识换页
不指定参数则默认使用 72 行为一页
同时指定则使用换页符(换页符优先级高于换行) - 输出打印机
–d xxx 使用 xxx 打印机为输出
- 分页模式
代码阅读
Global Var
全局变量,在整个程序执行过程中使用的变量
- MAX_INT 用来判断输入页码是否合理
- filename 存储文件名
- err 存储错误信息。
程序具有良好的错误信息处理能力(一大片的)if err != nil return
Option Args
这里我们利用 go 封装的 pflag 包,方便的解析终端参数。
var anInt = flag.Ing("optionName", defaultValue, "Introduction")
可以将参数 optionName 绑定到 anInt 上,还可以有 bool,string 类型。这里绑定的是指针。Error Hanlde
这是错误信息处理函数。当有 error 时,打印错误信息,并终止程序。
MAIN FUNCTION
主程序入口。首先使用 flag 解析参数,然后处理参数(
handle_args
),有错误异常则终止;接着开始处理输入和输出(readAndWrite
)。在这里,如果送往打印机,我们也将处理的输入打印出来,方便查阅。Args Handle FUNCTION
从输入参数一个一个处理。
必选参数
由于初始和结束页码默认值为-1,所以利用-1判断是否页码输入完全
若输入完全,判断初始页码是否合法,结束页码是否合法可选参数
判断分页模式。如果为行数分页,判断输入行数是否合法
Read File FUNCTION
处理输入和输出
首先默认输入为终端(os.Stdin
),如果输入参数后包含 argument,则视为文件输入,而且只选择第一个作为输入。处理输入信息
如果是分页符分页,那么循环读取,直到分页符时,页数加一;否则,循环读取,直到行数满足一页,则页数加一。
当页数符合指定页数时,将读取内容加入结果字符串。处理非法输入参数选项
因为输入的页码范围可能超出文件页码范围,这里我们约定这是非法的。所以读取的输入被丢弃。处理输出
如果输出参数的绑定值不是”default”,则指定打印机,我们使用exec.Command("command", args, ...)
调用子进程执行命令。
这里,由于我们自己的虚拟机没有打印机,所以有标准错误抛出,为了打印标准错误,我们需要手动获取其错误信息。
后记
到这里,程序就全部执行完了。这个程序代码,不是很长,但是,实现起来却有很多问题:
- pflag 的参数绑定,全部教程都只有一句话,参数会和他绑定,至于函数参数含义,都忽略不讲,视读者为大罗金仙,看一眼就看出源代码
- 文件的读取操作,熟悉切片的同学,可以毫无障碍的使用官方教程 os 库的读取文件,本人依旧习惯基础的读取操作,所以使用了 bufio 库,和 cpp,c的读取操作较为相似
- 执行命令实现打印输出,纠结了很久如何使用 pipe 完成任务,甚至考虑过先输出到文件再打开,利用 pipe 绑定到打印机(
忽略zz)。最后才明白,exec 库的 command,可以调用子进程执行终端命令。