用go实现linux命令行

用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 []string

func (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.Stdin
if 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
这是没有打印机
没有打印机导致错误
这是输出到屏幕
输出到屏幕
这是参数错误
参数错误
这是将lp命令换为cat的成功结果
换为cat

你可能感兴趣的:(go,linux)