命令行工具 selpg
selpg 允许用户指定从输入文本抽取的页的范围,这些输入文本可以来自文件或另一个进程。详情可见开发 Linux 命令行实用程序。
实现过程
为了解析命令行参数,需要安装 pflag 包:
go get github.com/spf13/pflag
首先使用 pflag 包定义命令行参数:
// flags
startPage := pflag.IntP("start page", "s", 0, "Start page to print")
endPage := pflag.IntP("end page", "e", 0, "End page to print")
pageLen := pflag.IntP("page length", "l", 72, "The number of lines in each page")
pageType := pflag.BoolP("page type", "f", false, "Whether '\\f' is page breaker or not")
printDest := pflag.StringP("print dest", "d", "", "The destination to print")
解析命令行参数并检验它们的合法性:
// parse flags
pflag.Parse()
// check flags
if *startPage < 0 || *endPage < 0 {
return errors.New("The page number should be positive.")
}
if *startPage > *endPage {
return errors.New("The start page number should be smaller than the end page number.")
}
if *pageLen != 72 && *pageType == true {
return errors.New("The \"-l\" flag and the \"-f\" flag shouldn't be used together.")
}
if *pageLen < 0 {
return errors.New("The page size should be positive.")
}
if pflag.NArg() > 1 {
return errors.New("Too many arguments.")
}
使用 bufio 包创建读取器:如果命令行中提供了文件名,则在文件中读取;否则在标准输入中读取。
// create reader
var reader *bufio.Reader
if pflag.NArg() == 1 {
// read from file
file, err := os.Open(pflag.Arg(0))
if err != nil {
return err
}
defer file.Close()
reader = bufio.NewReader(file)
} else {
// read from stdin
reader = bufio.NewReader(os.Stdin)
}
如果设定了 -f
标志,则以 -f
为间隔符逐页读取;否则逐行读取,并根据默认的或用户设置的行数来确定每个页的大小。最后根据用户设置的页数范围将所需的内容写入缓冲区。
// write target pages to buffer
var buf strings.Builder
if *pageType == true {
// read one page each time
pageCount := 0
for {
page, err := reader.ReadBytes('\f')
if err == io.EOF {
break
} else if err != nil {
return err
}
pageCount += 1
if pageCount >= *startPage && pageCount <= *endPage {
buf.Write(page)
} else if pageCount > *endPage {
break
}
}
} else {
// read one line each time
pageCount := 0
lineCount := 0
for {
line, err := reader.ReadBytes('\n')
if err == io.EOF {
break
} else if err != nil {
return err
}
lineCount += 1
if lineCount > *pageLen {
pageCount += 1
lineCount = 1
}
if pageCount >= *startPage && pageCount <= *endPage {
buf.Write(line)
} else if pageCount > *endPage {
break
}
}
}
如果用户没有设置输出位置,则直接将结果输出至标准输出;而如果用户指定了打印机的位置,则调用 lp
命令来将结果输出至目标打印机中。
// write buffer to destination
if *printDest == "" {
// write to stdout
fmt.Printf("%s", buf.String())
} else {
// write to printer
cmd := exec.Command("lp", "-d" + *printDest)
cmd.Stdin = strings.NewReader(buf.String())
var stderr bytes.Buffer
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
return fmt.Errorf("Write to printer failed with %s.\n Message: %s\n", err, stderr.Bytes())
}
}
最后,使用 Go 工具构建并安装该程序:
go install github.com/whichxjy/Service-Computing-Homework/selpg