服务计算--golang开发简单CLI程序

服务计算–golang开发简单CLI程序

这次作业内容看似复杂,老师要求我们用go开发一个简单的CLI程序selpg.go。这是一个命令行界面的应用程序,目的是支持输入参数从而按给定的参数实现快速打印。实际上,selpg.c的源码已经有了,我们需要的只是在此基础上把c语言改成go语言即可。目的是考察我们对go的掌握情况。
话不多说,先上源码。selpg项目

一、CLI是什么

CLI(Command Line Interface)是用户在命令行下交互的程序,由于通过将程序编译到一个静态文件中来减少依赖。在此处,我们的CLI要实现的功能是在命令行下通过输入的参数实现快速打印。

二、selpg.c源码解析

首先,作者定义个一个名为selpg_args的sruct用来存放处理过后的输入信息。

struct selpg_args
{
	int start_page;
	int end_page;
	char in_filename[BUFSIZ];
	int page_len; /* default value, can be overriden by "-l number" on command line */
	int page_type; /* 'l' for lines-delimited, 'f' for form-feed-delimited */
					/* default is 'l' */
	char print_dest[BUFSIZ];
};

之后,是main函数。要做的仅仅是创建一个selpg_args的结构体,然后初始化结构体。接下来从命令行读数据,存入struct。最后处理这个额struct即可.

int main(int ac, char **av)
{
	sp_args sa;

	/* save name by which program is invoked, for error messages */
	progname = av[0];

	sa.start_page = sa.end_page = -1;
	sa.in_filename[0] = '\0';
	sa.page_len = 72;
	sa.page_type = 'l';
	sa.print_dest[0] = '\0';

	process_args(ac, av, &sa);
	process_input(sa);

	return 0;
}c

用来从命令行读取参数,并将这些参数转化为srtuct结构体的数据的函数。

void process_args(int ac, char **av, sp_args* psa)

用来处理输入后srtuct的函数。(文件操作)

void process_input(sp_args sa)

如果编译之后,我们就可以在命令行中运行。

selpg -s startPage -e endPage [-l linePerPage | -f ][-d dest] filename

-s表示开始打印的页码,-e表示结束打印的页码,这两个必须写上;而-l表示按固定行数打印文件,-f表示按照换页符来打印,默认按行;-d则是打印的目的地,默认为屏幕。

三、将selpg.c改写为golang

首先介绍一个flag包,flag可以自动帮我们解析绑定在它身上的给定参数,以及为我们生成合适的help信息。这样我们就可以简化处理读入的参数了。
Golang之使用Flag和Pflag
可以使用民间大神的pflag,更友好。
之后就是改写代码了。
首先导入引用包:

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

struct改写:

type  selpg_args struct {
	start_page int
	end_page int
	in_filename string
	page_len int  /* default value, can be overriden by "-l number" on command line */
	page_type string  /* 'l' for lines-delimited, 'f' for form-feed-delimited */
								/* default is 'l' */
	print_dest string
}

process_args的改写,运用flag包:

func process_args(sa * sp_args) {
	flag.IntVarP(&sa.start_page,"start",  "s", -1, "start page(>1)")
	flag.IntVarP(&sa.end_page,"end", "e",  -1, "end page(>=start_page)")
	flag.IntVarP(&sa.page_len,"len", "l", 72, "page len")
	flag.StringVarP(&sa.page_type,"type", "f", "l", "'l' for lines-delimited, 'f' for form-feed-delimited. default is 'l'")
	flag.Lookup("type").NoOptDefVal = "f"
	flag.StringVarP(&sa.print_dest,"dest", "d", "", "print dest")

process_input的改写,只是简单的变换下语言。

func process_input(sa sp_args) {
	var fin *os.File /* input stream */
	/* set the input source */
	if len(sa.in_filename) == 0 {
		fin = os.Stdin
	} else {
		var err error
		fin, err = os.Open(sa.in_filename)
		if err != nil {
			fmt.Fprintf(os.Stderr, "\n%s: could not open input file \"%s\"\n",
				progname, sa.in_filename)
			os.Exit(7)
		}
		defer fin.Close()
	}

	/* set the output destination */
	bufFin := bufio.NewReader(fin)
	var fout io.WriteCloser
	cmd := &exec.Cmd{}

四、测试

为了方便测试,我把每页最大行数改为5

1.selpg -s 1 -e 1 input.txt / selpg -s 1 -e 3 input.txt

从第一页打到第三页 / 第一页打到第5页
服务计算--golang开发简单CLI程序

2.selpg -s 1 -e 1 -l 2 input.txt

从第1页打到第1页第2行
服务计算--golang开发简单CLI程序

3.selpg -s 1 -e 3 < input.txt

从第1页打到第3页,跟第一个命令一样。
服务计算--golang开发简单CLI程序

4.selpg -s 1 -e 3 input.txt > output.txt

第1页到第3页打印到output.txt。
服务计算--golang开发简单CLI程序

5.selpg -s 1 -e 10 input.txt 2> error.txt

错误信息打到error,由于我这里只有1-16行,所以第10页超出(只有4页)。
服务计算--golang开发简单CLI程序

6.selpg -s 1 -e 10 input.txt > /dev/null

不想把输出打到屏幕,只想在屏幕打出错误信息。
服务计算--golang开发简单CLI程序