服務計算03——Golang開發CLI命令行實用程序

CLI(Command Line Interface)實用程序是Linux下應用開發的基礎。Linux提供了cat、ls、copy等命令與操作系統交互;go語言提供一組實用程序完成從編碼、編譯、庫管理、產品發佈全過程支持。在開發領域,CLI在編程、調試、運維、管理中提供了圖形化程序不可替代的靈活性與效率。

Selpg功能概述

  • selpg 是從文本輸入選擇頁範圍的實用程序。它從標準輸入或從作爲命令行參數給出的文件名讀取文本輸入,允許用戶指定來自該輸入並隨後將被輸出的頁面範圍。在很多情況下,可以避免打印浪費,節省了資源。
  • 如用如下的命令,將需要的頁面打印出來
$ selpg -s 1 -e 2 input.txt //將input.txt的第一頁到第二頁輸出到屏幕
  • selpg 是以在 Linux 中創建命令的事實上的約定爲模型創建的,這些約定包括:

    • 獨立工作
    • 在命令管道中作爲組件工作(通過讀取標準輸入或文件名參數, 以及寫至標準輸出和標準錯誤)
    • 接受修改其行爲的命令行選項

Selpg程序邏輯

“-sNumber”和“-eNumber”強制選項:

selpg 要求用戶用兩個命令行參數“-sNumber”(例如,“-s10”表示從第 10 頁開始)和“-eNumber”(例如,“-e20”表示在第 20 頁結束)指定要抽取的頁面範圍的起始頁和結束頁。selpg 對所給的頁號進行合理性檢查;換句話說,它會檢查兩個數字是否爲有效的正整數以及結束頁是否不小於起始頁。這兩個選項,“-sNumber”和“-eNumber”是強制性的,而且必須是命令行上在命令名 selpg 之後的頭兩個參數

  • 程序實現:
if args[1][0] != '-' || args[1][1] != 's' {
		fmt.Fprintf(os.Stderr, "%s: Please use format: -s number\n", progname)
		os.Exit(1)
	}
	//獲取開始頁
	start, _ := strconv.Atoi(args[1][2:])
	if start < 1 {
		fmt.Fprintf(os.Stderr, "%s: Start page cannot be %d\n", progname, start)
		os.Exit(1)
	}
	carg.start_page = start
	//第二個參數
	if args[2][0] != '-' || args[2][1] != 'e' {
		fmt.Fprintf(os.Stderr, "%s: Please use format: -e number\n", progname)
		os.Exit(1)
	}
	//獲取結束頁
	end, _ := strconv.Atoi(args[2][2:])
	if end < 1 || end < start {
		fmt.Fprintf(os.Stderr, "%s: End page cannot be %d\n", progname, end)
		os.Exit(1)
	}

“-lNumber”和“-f”可選選項:
selpg 可以處理兩種輸入文本:

類型 1:該類文本的頁行數固定。這是缺省類型,因此不必給出選項進行說明。也就是說,如果既沒有給出“-lNumber”也沒有給出“-f”選項,則 selpg 會理解爲頁有固定的長度(每頁 72 行)。

$ selpg -s10 -e20 -l66

類型 2:該類型文本的頁由 ASCII 換頁字符(十進制數值爲 12,在 C 中用“\f”表示)定界。該格式與“每頁行數固定”格式相比的好處在於,當每頁的行數有很大不同而且文件有很多頁時,該格式可以節省磁盤空間。在含有文本的行後面,類型 2 的頁只需要一個字符 ― 換頁 ― 就可以表示該頁的結束。打印機會識別換頁符並自動根據在新的頁開始新行所需的行數移動打印頭。

$ selpg -s10 -e20 -f
  • 程序實現:
switch args[index][1] {
		case 'l':
			//獲取頁長
			pl, _ := strconv.Atoi(args[index][2:])
			if pl < 1 {
				fmt.Fprintf(os.Stderr, "%s: The page length cannot smaller than %d\n", progname, pl)
				os.Exit(1)
			}
			carg.page_len = pl
			index++
		case 'f':
			if len(args[index]) > 2 {
				fmt.Fprintf(os.Stderr, "%s: The option should be \"-f\"\n", progname)
				os.Exit(1)
			}
			carg.page_type = 'f'
			index++
if carg.page_type == 'l' {
				if line_count > carg.page_len {  //按給定行數換頁
					line_count = 1
					page_count++
				}
			} else {
				if string(line) == "\f" { //按分頁符換頁
					page_count++
				}
			}

“-dDestination”可選選項:

selpg 還允許用戶使用“-dDestination”選項將選定的頁直接發送至打印機。這裏,“Destination”應該是 lp 命令“-d”選項(請參閱“man lp”)可接受的打印目的地名稱。該目的地應該存在 ― selpg 不檢查這一點。在運行了帶“-d”選項的 selpg 命令後,若要驗證該選項是否已生效,請運行命令“lpstat -t”。該命令應該顯示添加到“Destination”打印隊列的一項打印作業。如果當前有打印機連接至該目的地並且是啓用的,則打印機應打印該輸出。這一特性是用 popen() 系統調用實現的,該系統調用允許一個進程打開到另一個進程的管道,將管道用於輸出或輸入。

selpg -s10 -e20 -dlp1

該命令將選定的頁作爲打印作業發送至 lp1 打印目的地

  • 程序實現:
case 'd':
			if len(args[index]) <= 2 {
				fmt.Fprintf(os.Stderr, "%s: -d option requires a output file\n", progname)
				os.Exit(1)
			}
			carg.destination = args[index][2:]
			index++
	if carg.destination != "" {
		cmd = exec.Command("bash", "-c", carg.destination)
		in, _ = cmd.StdinPipe()
		out, _ = cmd.StdoutPipe()
		cmd.Start()
	}
  • 程序的參數結構體如下:
//selpg的參數
type selpg_args struct {
	start_page  int
	end_page    int
	input_file  string
	destination string
	page_len    int //頁長
	page_type   int //換頁方式
}

具體實現見完整版代碼吧

測試Selpg

  1. 將input.txt文件第一頁到第二頁的內容輸出到屏幕
$ selpg -s1 -e2 input.txt

在這裏插入圖片描述
2.將input.txtx第一頁的內容輸出到屏幕

$ selpg -s1 -e1 < input.txt

在這裏插入圖片描述
3. 將input.txt中第二頁到第四頁的內容輸出到output.txt

$ selpg -s2 -e4 input.txt > output.txt

在這裏插入圖片描述
在這裏插入圖片描述
4. 由換頁符決定換頁,將input.txt第一頁的內容輸出到屏幕

$ selpg -s1 -e1 -f input.txt

在這裏插入圖片描述
5. 將第一頁發送至命令cat,將input.txt第一頁的前五行輸出到屏幕

$ selpg -s1 -e1 -l5 -dcat input.txt

在這裏插入圖片描述
6. 將第二頁至第三頁的前四行寫入output.txt和error.txt
在這裏插入圖片描述在這裏插入圖片描述
7. 將錯誤消息顯示至error.txt
在這裏插入圖片描述
在這裏插入圖片描述

代碼傳送門

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章