服務計算-用go語言開發CLI命令行實用程序-Selpg

1、Selpg的介紹

selpg 允許用戶指定從輸入文本抽取的頁的範圍,這些輸入文本可以來自文件/標準輸入/另一個進程。

2、具體要求

實現指令的要求請查看該鏈接

3、實現具體思路

查看selpg 的 C 代碼,在此基礎上實現。

3.1引入的包

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"os/exec"
)

os,flag包,簡單處理參數;bufio處理緩存

3.2相關結構體

按照C語言設置對應結構體和全局變量:

type selpgargs struct {
	start_page  int         //開始的頁編號
	end_page    int         //結束的頁編號
	in_filename  string
	print_dest string
	page_len    int     /* default value, can be overriden by "-l number" on command line */
	page_type bool  /* 'l' for lines-delimited, 'f' for form-feed-delimited */
}

var progname string     /* program name, for error messages */

3.3主函數處理流程

初始化參數結構體-處理參數-根據參數進行處理

func main() {
	progname = os.Args[0]    /* save name by which program is invoked, for error messages */
	var args selpgargs  
	FlagInit(&args)         //初始化參數標記
	process_args(&args)      //處理參數
	process_input(&args)     //根據用戶輸入的各個參數進行相應的操作
}

3.4FlagInit函數:

  1. 任務:進行指令結構體的標記的初始化
  2. 實現:參考C語言版本的實現及flag包的用法
  3. flag的簡單使用:
    A.定義flags有兩種方式:

1)flag.Xxx(),其中Xxx可以是Int、String等;返回一個相應類型的指針,如:

var ip = flag.Int("flagname", 1234, "help message for flagname")

2)flag.XxxVar(),將flag綁定到一個變量上,如:

var flagvar int
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")

另外,還可以創建自定義flag,只要實現flag.Value接口即可(要求receiver是指針),這時候可以通過如下方式定義該flag:

flag.Var(&flagVal, "name", "help message for flagname

B. 解析參數(Parse):從參數列表中解析定義的flag。參數arguments不包括命令名,即應該是os.Args[1:]。
4. 代碼:

//initial flags
func FlagInit(args *selpgargs) {
	flag.IntVar(&args.start_page, "s", -1, "Start page.")
	flag.IntVar(&args.end_page, "e", -1, "End page.")
	flag.IntVar(&args.page_len, "l", 72, "page_len.")
	flag.BoolVar(&args.page_type, "f", false, "page_type")
	flag.StringVar(&args.print_dest, "d", "", "print_dest")
	flag.Usage = usage
	flag.Parse()
}

3.5 process_args函數:

  1. 任務:處理參數
  2. 實現:參考C語言版本
  3. 代碼:
func process_args(args *selpgargs) {
	if args == nil {
        fmt.Fprintf(os.Stderr, "\n[Error]The args is nil!Please check your program!\n\n")
        os.Exit(1)
    }
    if args.start_page == -1 || args.end_page == -1 {
		fmt.Fprintf(os.Stderr, "\n[Error]:%s, not enough arguments\n\n", progname)
		flag.Usage()
		os.Exit(2)
	}

	if os.Args[1][0] != '-' || os.Args[1][1] != 's' {
		fmt.Fprintf(os.Stderr, "\n[Error]:%s, 2st arg should be -sstart_page\n\n", progname)
		flag.Usage()
		os.Exit(3)
	}

	end_index := 2
	if len(os.Args[1]) == 2 {
		end_index = 3
	}

	if os.Args[end_index][0] != '-' || os.Args[end_index][1] != 'e' {
		fmt.Fprintf(os.Stderr, "\n[Error]:%s, 3st arg should be -eend_page\n\n", progname)
		flag.Usage()
		os.Exit(4)
	}

	if args.start_page > args.end_page || args.start_page < 0 ||
		args.end_page < 0 {
		fmt.Fprintln(os.Stderr, "\n[Error]:Invalid arguments")
		flag.Usage()
		os.Exit(5)
	}

}

3.6 process_input函數:

  1. 任務:進行操作
  2. 實現:參考C語言版本以及os/exec 庫,bufio包的用法
  3. 代碼:
func process_input(args *selpgargs) {
	var stdin io.WriteCloser
	var err error
	var cmd *exec.Cmd

	if args.print_dest != "" {
		cmd = exec.Command("cat", "-n")
		stdin, err = cmd.StdinPipe()
		if err != nil {
			fmt.Println(err)
		}
	} else {
		stdin = nil
	}

	if flag.NArg() > 0 {
		args.in_filename = flag.Arg(0)
		output, err := os.Open(args.in_filename)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		reader := bufio.NewReader(output)
		if args.page_type {
			for pageNum := 0; pageNum <= args.end_page; pageNum++ {
				line, err := reader.ReadString('\f')
				if err != io.EOF && err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				if err == io.EOF {
					break
				}
				printOrWrite(args, string(line), stdin)
			}
		} else {
			count := 0
			for {
				line, _, err := reader.ReadLine()
				if err != io.EOF && err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				if err == io.EOF {
					break
				}
				if count/args.page_len >= args.start_page {
					if count/args.page_len > args.end_page {
						break
					} else {
						printOrWrite(args, string(line), stdin)
					}
				}
				count++
			}

		}
	} else {
		scanner := bufio.NewScanner(os.Stdin)
		count := 0
		target := ""
		for scanner.Scan() {
			line := scanner.Text()
			line += "\n"
			if count/args.page_len >= args.start_page {
				if count/args.page_len <= args.end_page {
					target += line
				}
			}
			count++
		}
		printOrWrite(args, string(target), stdin)
	}

	if args.print_dest != "" {
		stdin.Close()
		cmd.Stdout = os.Stdout
		cmd.Run()
	}
}

3.7 測試代碼

  1. 簡單測試:
    在這裏插入圖片描述
  2. 重定向測試
    在這裏插入圖片描述
    在這裏插入圖片描述
  3. 輸出到2.txt:
    在這裏插入圖片描述
  4. 錯誤提示:
    在這裏插入圖片描述
  5. 默認行數:
    在這裏插入圖片描述
  6. 管道輸送至命令“lp -dlp1”:
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章