Fork me on GitHub

Selpg-WithGO

Selpg

Selpg 是实用的命令行程序,它可以读取终端输入或文件输入,然后根据给定参数,打印输入的指定位置。这是最初开发者的教学链接

不得不说,和别人的差距是很明显的。无论是编程规范,还是博客水准。在这里就不介绍命令行程序的规范和准则了,最初开发者的博客已经非常详细了。本文为指导博客,讲解阅读源代码和开发过程。强烈建议在阅读下文前,理解原作者的博客。

规范约定

首先,我们需要约定重新开发的 Selpg 的使用规范。

输入输出

和原来一样,我们支持以下的规则:

  1. 终端输入
  2. 重定向输入
  3. 终端输出
  4. 指定输出

参数选项

  1. 必选参数
    我们必须指明开始页和终止页
  2. 可选参数
    • 分页模式
      –l x,指定一页为 x 行
      –f,使用换页符标识换页
      不指定参数则默认使用 72 行为一页
      同时指定则使用换页符(换页符优先级高于换行)
    • 输出打印机
      –d xxx 使用 xxx 打印机为输出

代码阅读

代码地址

  1. Global Var

    全局变量,在整个程序执行过程中使用的变量

    • MAX_INT 用来判断输入页码是否合理
    • filename 存储文件名
    • err 存储错误信息。
      程序具有良好的错误信息处理能力(一大片的if err != nil return)
  2. Option Args

    这里我们利用 go 封装的 pflag 包,方便的解析终端参数。var anInt = flag.Ing("optionName", defaultValue, "Introduction") 可以将参数 optionName 绑定到 anInt 上,还可以有 bool,string 类型。这里绑定的是指针。

  3. Error Hanlde

    这是错误信息处理函数。当有 error 时,打印错误信息,并终止程序。

  4. MAIN FUNCTION

    主程序入口。首先使用 flag 解析参数,然后处理参数(handle_args),有错误异常则终止;接着开始处理输入和输出(readAndWrite)。在这里,如果送往打印机,我们也将处理的输入打印出来,方便查阅。

  5. Args Handle FUNCTION

    从输入参数一个一个处理。

    1. 必选参数

      由于初始和结束页码默认值为-1,所以利用-1判断是否页码输入完全
      若输入完全,判断初始页码是否合法,结束页码是否合法

    2. 可选参数

      判断分页模式。如果为行数分页,判断输入行数是否合法

  6. Read File FUNCTION

    • 处理输入和输出
      首先默认输入为终端(os.Stdin),如果输入参数后包含 argument,则视为文件输入,而且只选择第一个作为输入。

    • 处理输入信息
      如果是分页符分页,那么循环读取,直到分页符时,页数加一;否则,循环读取,直到行数满足一页,则页数加一。
      当页数符合指定页数时,将读取内容加入结果字符串。

    • 处理非法输入参数选项
      因为输入的页码范围可能超出文件页码范围,这里我们约定这是非法的。所以读取的输入被丢弃。

    • 处理输出
      如果输出参数的绑定值不是”default”,则指定打印机,我们使用exec.Command("command", args, ...)调用子进程执行命令。
      这里,由于我们自己的虚拟机没有打印机,所以有标准错误抛出,为了打印标准错误,我们需要手动获取其错误信息。

后记

到这里,程序就全部执行完了。这个程序代码,不是很长,但是,实现起来却有很多问题:

  1. pflag 的参数绑定,全部教程都只有一句话,参数会和他绑定,至于函数参数含义,都忽略不讲,视读者为大罗金仙,看一眼就看出源代码
  2. 文件的读取操作,熟悉切片的同学,可以毫无障碍的使用官方教程 os 库的读取文件,本人依旧习惯基础的读取操作,所以使用了 bufio 库,和 cpp,c的读取操作较为相似
  3. 执行命令实现打印输出,纠结了很久如何使用 pipe 完成任务,甚至考虑过先输出到文件再打开,利用 pipe 绑定到打印机(忽略zz)。最后才明白,exec 库的 command,可以调用子进程执行终端命令。