用go实现linux命令行

来源:互联网 发布:sql视图是什么 编辑:程序博客网 时间:2024/04/19 00:58

用go实现linux命令行

要求:实现selpg命令,使用Go语言

以下为该命令参数形式

-s start_page -e end_page [ -f | -l lines_per_page ] [ -d dest ] [ in_filename ]

各参数意义如下

-s start page 表示打印开始的页数
-e end page 表示打印结束页数
-f 可选,表示文件是否以\f作为分页标志,与-l不能一起使用
-l 可选,表示文件几行作为一页,与-f不能一起使用
-d 可选,目标打印机
in_filename 可选,读入的文件,若不选则从标准流输入

A.关于实现过程个人觉得关键几个部分

1.关于字符串部分

根据老师教程是用os包获取命令行参数然后用flag包解析参数
这里os包只需简单调用os.Arg来获取参数即可,这里我们说一下flag包,flag包一般用来解析命令行参数
flag包主要包含一些方法和一个flagSet,后者只是对前者做了封装,这里我选择了用flagSet

/*函数原型*/func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet/*例子*/flagSet   = flag.NewFlagSet(os.Args[0], flag.ExitOnError)

这是创建一个flagSet,其中第一个参数是程序名字,第二个是参数错误时的错误处理方法
这里os.Arg[0]是程序名字,然后我选择了错误时就终止程序的类型
接下来是定义几个参数

startPage = flagSet.Uint("s", 0, "tart_page, must be specified and greter than 0")endPage   = flagSet.Uint("e", 0, "end_page, must be specified and greter than 0")pageLen   = flagSet.String("l", "", "page_size, exclusive to -f, must be postive,default is 72")pageType  = flagSet.Bool("f", false, "use \\f to divide pages, exclusive to -l")

以上的几个方法将会解析参数并将对应指针返回,对应的几个参数分别为参数的flag,参数默认值,参数描述
这是函数原型,创建flagSet对象后通过以上可方法定义参数

func Uint(name string, value uint, usage string) *uint

定义了参数后我们可以通过调用Parse方法,flagSet就会帮我们解析命令行内输入的字符串然后赋值给对应指针,如果用户写的参数错误就会按照你选择的错误方式处理
这里我还自定义了一种类型,flag中你可以通过Var等方法来给参数赋值自定义类型,但要实现Set()和String()两个接口用于赋值和转字符串
下面是我代码中的例子

type StringArray []stringfunc (s *StringArray) Set(value string) error {    *s = append(*s, value)    return nil}func (s *StringArray) String() string {    return fmt.Sprint([]string(*s))}func (s *StringArray) Size() int {    return len(*s)}func (s *StringArray) Top() (string, error) {    if s.Size() > 0 {        var temp = s.String()        temp = strings.TrimSuffix(temp, "[")        temp = strings.TrimSuffix(temp, "]")        return temp, nil    }    return "", fmt.Errorf("empty error")}

根据官网文档建议
If you like, you can bind the flag to a variable using the Var() functions.

var flagvar int
func init() {
flag.IntVar(&flagvar, “flagname”, 1234, “help message for flagname”)
}

因此我在init函数里面对我的一个参数进行了定义

flagSet.Var(&printDest, "d", "destination")

剩下的就是获得参数后大概判断是不是合法参数,这些想必不是什么难点写写判断就可以

2.关于流和读取文件还有lp命令部分

关于流部分,首先要确定接受文件的流从哪输入过来
如果没有文件参数的话就是标准流,有的话就用文件流

var inputStream = os.Stdinif inputFile != "" {    inputStream, err = os.Open(inputFile)    defer inputStream.Close()    if err != nil {        fmt.Fprintf(os.Stderr, "%s : ", programname)        fmt.Fprintln(os.Stderr, err)        os.Exit(1)    }}

这里使用os的open函数来打开文件流
然后关于这个流要输出到哪里,我们需要确定,如果存在目的打印机我们把我们读取的文件通过管道传到lp命令的输入流,这里我用bufio的reader来读文件,然后调用os/exec的StdinPipe()方法来将文件输入,当然如果用户没定义-d参数则将输出流输出到屏幕上即可
关键代码如下

stdin = os.Stdout    if printDest.Size() > 0 && pDest != "" {        printer = exec.Command("lp", "-d", pDest)        //printer = exec.Command("cat")        stdin, printErr = printer.StdinPipe()        if printErr != nil {            fmt.Fprintf(os.Stderr, "%s : ", programname)            fmt.Fprintln(os.Stderr, printErr)        }        if *pageType {            err = writeIntoPrintInByF(myReader, *startPage, *endPage)        } else {            err = writeIntoPrintInByLine(myReader, *startPage, *endPage, pLen)        }        if err != nil {            fmt.Fprintf(os.Stderr, "%s : ", programname)            fmt.Fprintln(os.Stderr, err)        }        stdin.Close()

然后这是将读取文件写入流中,这里我调用了Write方法

stdin.Write([]byte(line))

其中line是我调用reader的readString方法获得的字符串,当然也有其他库函数实现读取字符串

line, err := reader.ReadString('\n')

最后是启动命令,这里如果命令出错我们要杀进程,这里我用timer监听实现

printer.Stdout = os.Stdout        printer.Stderr = os.Stderr        if err = printer.Start(); err != nil {            fmt.Fprintf(os.Stderr, "%s : ", programname)            fmt.Fprintln(os.Stderr, printErr)        }        timer := time.AfterFunc(3*time.Second, func() {            printer.Process.Kill()        })        err = printer.Wait()        timer.Stop()
3.关于源码

源码位于我的github:https://github.com/caijh23/Go/tree/master/selpg
代码分为两个文件args.go和slepg.go分别为上述讲的两个部分

4.结果展示

a.txt里面有两行数据均为123
这是没有打印机
Alt text没有打印机导致错误
这是输出到屏幕
Alt text输出到屏幕
这是参数错误
Alt text参数错误
这是将lp命令换为cat的成功结果
Alt text换为cat

原创粉丝点击