Golang CLI程序构建学习
作业要求,以及学习参考资料
https://pmlpml.gitee.io/service-computing/post/ex-cli-basic/
本次作业是模仿一个比较简单的CLI程序(基于C语言),用golang重写一遍
原CLI创建要求及其 学习
参考https://www.ibm.com/developerworks/cn/linux/shell/clutil/index.html
在此之前,需要了解一些基础知识
CLI程序:可以在终端中直接直接调用的程序
flag的作用:在CLI程序中,会有许多可选择的参数,例如 “selpg -s 100 -e 200”等,利用flag,可以直接获取s,和e参数的值
必选参数:例如 “gcc code.c” 必须要输入的文件等等
为啥要用Pflag,而不是用flag呢?(当然,我也没有很搞懂,但是它们的使用方法是类似的)
pflag 包与 flag 包的工作原理甚至是代码实现都是类似的,下面是 pflag 相对 flag 的一些优势:
- 支持更加精细的参数类型:例如,flag 只支持 uint 和 uint64,而 pflag 额外支持 uint8、uint16、int32 等类型。
- 支持更多参数类型:ip、ip mask、ip net、count、以及所有类型的 slice 类型。
- 兼容标准 flag 库的 Flag 和 FlagSet:pflag 更像是对 flag 的扩展。
- 原生支持更丰富的功能:支持 shorthand、deprecated、hidden 等高级功能。
除此之外,还需要了解 io 与 bufio的关系,用于文件的读写
go的io库里,读写文件的方法很难用,因此需要把io封装在bufio中。使用bufio的方法,可以更加方便
对于io和bufio的学习,参考https://blog.csdn.net/houyanhua1/article/details/88760853
最后,还需要学习os/exec中的 exec.Command(”命令名字“,“参数”),用来执行可能需要的打印命令
https://www.godoc.org/os/exec#example-Cmd-StdinPipe
通过官方文档的学习,了解到exec.Command()会返回*Cmd文件,可以用它来控制命令的输入和输出位置
代码简析:
CLI 命令行参数,存储的位置
main函数,先获取CLI命令行参数,然后检查是否要把内容送去打印机,确定输出位置。最后运行t检索input内容,输出。
检查是否有打印地址参数
用Pflag和os.Args获取命令行参数
处理input内容函数
使用selpg,根据要求网页的 使用selpg
每一个数字是一行
每一个数字是一页
由于没有默认打印机,所以出现了报错
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | package main import flag "github.com/spf13/pflag" import ( "fmt" "os" "io" "bufio" "os/exec" ) var ( h bool start_page, end_page, page_len int //differ page ends for limited line or \f page_type bool print_dest, in_fileName string ) var ( writer io.WriteCloser ) func main(){ process_args() // writer = os.Stdout if print_dest != "" { t_cmd := exec.Command( "lp" , "-d" + print_dest) var err error if writer, err = t_cmd.StdinPipe(); err != nil { fmt.Fprintf(os.Stderr, "could not open pipe" ) return } t_cmd.Stdout = os.Stdout t_cmd.Stderr = os.Stderr if err := t_cmd.Start(); err != nil { fmt.Fprintf(os.Stderr, "cmd start error" ) return } } if h { flag.Usage() return } process_input() } func process_args(){ in_fileName = os.Args[len(os.Args)-1] flag.BoolVarP(&h, "help" , "h" , false, "this help" ) flag.IntVarP(&start_page, "start_page" , "s" , -1, "input the start page number" ) flag.IntVarP(&end_page, "end_page" , "e" , -1, "input the end page number" ) flag.IntVarP(&page_len, "page_len" , "l" , 72, "input the page length" ) flag.BoolVarP(&page_type, "page_type" , "f" , false, "input the page type -f page end with \\f" ) flag.StringVarP(&print_dest, "print_dest" , "d" , "" , "input the print destination" ) flag.Parse(); flag.Usage = usage } func process_input() { // check the start page and the end page if start_page == -1 || start_page < 0{ fmt.Fprintf(os.Stderr, "start page must be set" ) return } else if end_page == -1 || end_page < 0{ fmt.Fprintf(os.Stderr, "end page must be set" ) return } else if start_page > end_page { fmt.Fprintf(os.Stderr, "start page must less or equal to the end page" ) return } file, err := os.Open(in_fileName) rFile := bufio.NewReader(file) rFile = bufio.NewReader(file) if (err != nil) { //fmt.Println("a correct file name is necessary, open file Error! :", err) rFile = bufio.NewReader(os.Stdin) } current_page := 1 if (page_type) { for page, err := rFile.ReadBytes( '\f' ); current_page <= end_page; page, err = rFile.ReadBytes( '\f' ) { if err == io.EOF { fmt.Println( "the file doesn't have enough pages" ) } if current_page >= start_page { writer.Write(page) } current_page += 1 } } else { lineNum := 1 for line, err := rFile.ReadBytes( '\n' ); current_page <= end_page; line, err = rFile.ReadBytes( '\n' ) { if err == io.EOF { fmt.Println( "the file doesn't have enough pages" ) } if current_page >= start_page { writer.Write(line) } lineNum = lineNum + 1 if (lineNum == page_len + 1) { current_page += 1 lineNum = 1 } } } } func usage() { fmt.Fprintf(os.Stderr, "selpg Usage: selpg [-h] [-s start_page] [-e end_page] [-l page_len] [-f page_type] in_fileName\nOptions\n" ) flag.PrintDefaults() } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」