使用golang开发简单的 CLI 程序 selpg

设计说明

CLI(Command Line Interface)实用程序是Linux下应用开发的基础。在开发领域,CLI在编程、调试、运维、管理中提供了图形化程序不可替代的灵活性与效率。这次的主要任务是使用golang开发Linux命令行实用程序中的selpg。

代码简介

完整代码链接:http://139.9.57.167:20080/share/bmdov4676kvrcg19tfg0?secret=false

由于老师要求使用 pflag 替代 goflag 以满足 Unix 命令行规范,所以我们需要安装和导入pflag,这一步实现可以在vsc的终端中输入如下命令:

go get -u "github.com/spf13/pflag"

然后我们需要在程序开头引入/需要的包:

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

接下来定义保存参数数据的结构体:

type selpgArgs struct {
	startPage  int
	endPage    int
	inFileName string
	pageLen    int
	pageType   bool
	printDest  string
}

使用 pflag 替代 goflag 以满足 Unix 命令行规范:

func getArgs(args *selpgArgs) {

	pflag.IntVarP(&(args.startPage), "startPage", "s", -1, "Define startPage")
	pflag.IntVarP(&(args.endPage), "endPage", "e", -1, "Define endPage")
	pflag.IntVarP(&(args.pageLen), "pageLength", "l", 72, "Define pageLength")
	pflag.StringVarP(&(args.printDest), "printDest", "d", "", "Define printDest")
	pflag.BoolVarP(&(args.pageType), "pageType", "f", false, "Define pageType")
	pflag.Parse()

	argLeft := pflag.Args()
	if len(argLeft) > 0 {
		args.inFileName = string(argLeft[0])
	} else {
		args.inFileName = ""
	}
}

接下来用一个函数判断输入的命令的参数的正确性,如果有误,则指出错误并终止程序,如果无误则输出各参数:

func checkArgs(args *selpgArgs) {
	if (args.startPage == -1) || (args.endPage == -1) {
		fmt.Fprintf(os.Stderr, "\n[Error]起始页码和结尾页码不能为空\n")
		os.Exit(2)
	} else if (args.startPage <= 0) || (args.endPage <= 0) {
		fmt.Fprintf(os.Stderr, "\n[Error]起始页码和结尾页码不能为负数\n")
		os.Exit(3)
	} else if args.startPage > args.endPage {
		fmt.Fprintf(os.Stderr, "\n[Error]起始页码不能大于结尾页码\n")
		os.Exit(4)
	} else if (args.pageType == true) && (args.pageLen != 72) {
		fmt.Fprintf(os.Stderr, "\n[Error]不能同时使用-l -f\n")
		os.Exit(5)
	} else if args.pageLen <= 0 {
		fmt.Fprintf(os.Stderr, "\n[Error]页数不能小于1\n")
		os.Exit(6)
	} else {
		pageType := "page length."
		if args.pageType == true {
			pageType = "The end sign /f."
		}
		fmt.Printf("\n")
		fmt.Printf("起始页: %d\n末页: %d\n输入文件: %s\n页数: %d\n书页类型: %s\n输出文件: %s\n", args.startPage, args.endPage, args.inFileName, args.pageLen, pageType, args.printDest)
	}
}

当命令各参数无误时,就开始调用excute函数执行命令。该部分函数先检查输入,然后打开文件,检查是否出现错误,最后判断是否有-d参数。代码如下所示:

func excute(args *selpgArgs) {
	var fin *os.File
	if args.inFileName == "" {
		fin = os.Stdin
	} else {
		checkFileAccess(args.inFileName)
		var err error
		fin, err = os.Open(args.inFileName)
		checkError(err, "File input")
	}

	output(args.printDest, fin, args.startPage, args.endPage, args.pageLen, args.pageType)
}

func checkFileAccess(filename string) {
	_, errFileExits := os.Stat(filename)
	if os.IsNotExist(errFileExits) {
		fmt.Fprintf(os.Stderr, "\n[Error]: 输入文件 \"%s\" 不存在\n", filename)
		os.Exit(7)
	}
}

输出函数output将输入的文件,按页码要求读取并输出到fout中,此函数中也会判断分页方式:

func output(printDest string, fin *os.File, pageStart int, pageEnd int, pageLen int, pageType bool) {

	lineCount := 0
	pageCount := 1
	buf := bufio.NewReader(fin)

	var cmd *exec.Cmd
	var fout io.WriteCloser
	if len(printDest) > 0 {
		cmd, fout = cmdExec(printDest)
	}

	for true {

		var line string
		var err error
		if pageType {
			line, err = buf.ReadString('\f')
			pageCount++
		} else {
			line, err = buf.ReadString('\n')
			lineCount++
			if lineCount > pageLen {
				pageCount++
				lineCount = 1
			}
		}

		if err == io.EOF {
			break
		}
		checkError(err, "file read in\n")

		if (pageCount >= pageStart) && (pageCount <= pageEnd) {
			var outputErr error
			if len(printDest) == 0 {
				_, outputErr = fmt.Fprintf(os.Stdout, "%s", line)
			} else {
				_, outputErr = fout.Write([]byte(line))
				checkError(outputErr, "pipe input")
			}
			checkError(outputErr, "Error happend when output the pages.")
		}
	}

	if len(printDest) > 0 {
		fout.Close()
		errStart := cmd.Run()
		checkError(errStart, "CMD Run")
	}

	if pageCount < pageStart {
		fmt.Fprintf(os.Stderr, "\n[Error]: 起始页 (%d) 大于总页数 (%d), 无输出\n", pageStart, pageCount)
		os.Exit(9)
	} else if pageCount < pageEnd {
		fmt.Fprintf(os.Stderr, "\n[Error]: 末页 (%d) 大于总页数 (%d), 输出不全\n", pageEnd, pageCount)
		os.Exit(10)
	}
}

使用

在src文件夹下创建一个新的文件夹,命名为selpg,然后在文件夹里面放入go文件,使用命令

go install selpg

生成bin/selpg文件,然后在bin文件夹中放入测试文件,控制台上进入bin,就可以测试命令了。

测试结果

  1. $ selpg -s1 -e1 input_file
    使用golang开发简单的 CLI 程序 selpg_第1张图片
  2. selpg -s10 -e20 input_file >output_file

    这里可以看见在bin文件中生成了一个output文件(中文产生了乱码)
    使用golang开发简单的 CLI 程序 selpg_第2张图片
  3. selpg -s1 -e1 input_file 2>error_file
    使用golang开发简单的 CLI 程序 selpg_第3张图片
    这里可以看见这里可以看见在bin文件中生成了一个error_file文件(中文产生了乱码)
    使用golang开发简单的 CLI 程序 selpg_第4张图片
  4. selpg -s10 -e20 input_file >output_file 2>error_file
    使用golang开发简单的 CLI 程序 selpg_第5张图片

你可能感兴趣的:(学习)