Golang CLI程序构建学习

作业要求,以及学习参考资料

https://pmlpml.gitee.io/service-computing/post/ex-cli-basic/

 

本次作业是模仿一个比较简单的CLI程序(基于C语言),用golang重写一遍

原CLI创建要求及其 学习

参考https://www.ibm.com/developerworks/cn/linux/shell/clutil/index.html

在此之前,需要了解一些基础知识

 

CLI程序:可以在终端中直接直接调用的程序

flag的作用:在CLI程序中,会有许多可选择的参数,例如 “selpg  -s 100 -e 200”等,利用flag,可以直接获取s,和e参数的值

对于flag的学习,参考http://blog.studygolang.com/2013/02/%E6%A0%87%E5%87%86%E5%BA%93-%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%E8%A7%A3%E6%9E%90flag/

必选参数:例如 “gcc code.c” 必须要输入的文件等等

 

为啥要用Pflag,而不是用flag呢?(当然,我也没有很搞懂,但是它们的使用方法是类似的)

pflag 包与 flag 包的工作原理甚至是代码实现都是类似的,下面是 pflag 相对 flag 的一些优势:

  • 支持更加精细的参数类型:例如,flag 只支持 uint 和 uint64,而 pflag 额外支持 uint8、uint16、int32 等类型。
  • 支持更多参数类型:ip、ip mask、ip net、count、以及所有类型的 slice 类型。
  • 兼容标准 flag 库的 Flag 和 FlagSet:pflag 更像是对 flag 的扩展。
  • 原生支持更丰富的功能:支持 shorthand、deprecated、hidden 等高级功能。

 

除此之外,还需要了解 io 与 bufio的关系,用于文件的读写

go的io库里,读写文件的方法很难用,因此需要把io封装在bufio中。使用bufio的方法,可以更加方便

对于io和bufio的学习,参考https://blog.csdn.net/houyanhua1/article/details/88760853

 

最后,还需要学习os/exec中的 exec.Command(”命令名字“,“参数”),用来执行可能需要的打印命令

https://www.godoc.org/os/exec#example-Cmd-StdinPipe

通过官方文档的学习,了解到exec.Command()会返回*Cmd文件,可以用它来控制命令的输入和输出位置

 

代码简析:

CLI 命令行参数,存储的位置

 

main函数,先获取CLI命令行参数,然后检查是否要把内容送去打印机,确定输出位置。最后运行t检索input内容,输出。

 

检查是否有打印地址参数

 

 

 

用Pflag和os.Args获取命令行参数

 

处理input内容函数

 

使用selpg,根据要求网页的 使用selpg

每一个数字是一行

 

 

 

 

 

 

 

 

 

 

每一个数字是一页

 

由于没有默认打印机,所以出现了报错

 

 

完整代码:

 

package main

import flag "github.com/spf13/pflag"
import (
	"fmt"
	"os"
	"io"
	"bufio"
	"os/exec"
)


var (
	h bool
	start_page, end_page, page_len int
	//differ page ends for limited line or \f
	page_type bool 		
	print_dest, in_fileName string
)

var (
	writer io.WriteCloser
)

func main(){
	process_args()
	// 
	writer = os.Stdout
	if print_dest != "" {
		t_cmd := exec.Command("lp", "-d" + print_dest)
		var err error
		if writer, err = t_cmd.StdinPipe(); err != nil {
			fmt.Fprintf(os.Stderr, "could not open pipe")
			return
		}

		t_cmd.Stdout = os.Stdout
		t_cmd.Stderr = os.Stderr
		if err := t_cmd.Start(); err != nil {
			fmt.Fprintf(os.Stderr, "cmd start error")
			return 
		}
	}
	

	if h {
		flag.Usage()
		return 
	}
	process_input()
	
}

func process_args(){
	in_fileName = os.Args[len(os.Args)-1]
	flag.BoolVarP(&h, "help","h", false, "this help")
	flag.IntVarP(&start_page, "start_page", "s", -1, "input the start page number")
	flag.IntVarP(&end_page, "end_page", "e", -1, "input the end page number")
	flag.IntVarP(&page_len, "page_len", "l", 72, "input the page length")
	flag.BoolVarP(&page_type, "page_type", "f", false, "input the page type -f page end with \\f")
	flag.StringVarP(&print_dest, "print_dest", "d", "", "input the print destination")

	flag.Parse();
	flag.Usage = usage
}



func process_input()  {
	// check the start page and the end page  
	if start_page == -1 || start_page < 0{
		fmt.Fprintf(os.Stderr,"start page must be set")
		return
	}else if end_page == -1 || end_page < 0{
		fmt.Fprintf(os.Stderr,"end page must be set")
		return 
	}else if start_page > end_page {
		fmt.Fprintf(os.Stderr,"start page must less or equal to the end page")
		return 
	}
	file, err := os.Open(in_fileName)
	

	rFile := bufio.NewReader(file)
	rFile = bufio.NewReader(file)
	if (err != nil) {
		//fmt.Println("a correct file name is necessary, open file Error! :", err)
		rFile = bufio.NewReader(os.Stdin)
	}
	
	current_page := 1
	
	if (page_type) {
		for  page, err := rFile.ReadBytes('\f'); current_page <= end_page; page, err = rFile.ReadBytes('\f') {
			if err == io.EOF {
				fmt.Println("the file doesn't have enough pages")
			}
			
			if current_page >= start_page {
				writer.Write(page)
			}
			current_page += 1
		} 
	}else {
		lineNum := 1
		for line, err := rFile.ReadBytes('\n'); current_page <= end_page; line, err = rFile.ReadBytes('\n') {
			if err == io.EOF {
				fmt.Println("the file doesn't have enough pages")
			}
			if current_page >= start_page {
				writer.Write(line)
			}

			lineNum = lineNum + 1
			if (lineNum == page_len + 1) {
				current_page += 1
				lineNum = 1
			} 
		}
	}
	
}

func usage() {
	fmt.Fprintf(os.Stderr, "selpg Usage: selpg [-h] [-s start_page] [-e end_page] [-l page_len] [-f page_type] in_fileName\nOptions\n")
	flag.PrintDefaults()
}

 

posted @ 2020-10-08 23:28  woodx  阅读(297)  评论(0)    收藏  举报