CLI命令行实用程序开发基础

1.概述

CLI(Command Line Interface)实用程序是Linux下应用开发的基础。正确的编写命令行程序让应用与操作系统融为一体,通过shell或script使得应用获得最大的灵活性与开发效率。Linux提供了cat、ls、copy等命令与操作系统交互;go语言提供一组实用程序完成从编码、编译、库管理、产品发布全过程支持;容器服务如docker、k8s提供了大量实用程序支撑云服务的开发、部署、监控、访问等管理任务;git、npm等都是大家比较熟悉的工具。尽管操作系统与应用系统服务可视化、图形化,但在开发领域,CLI在编程、调试、运维、管理中提供了图形化程序不可替代的灵活性与效率。

2.基础知识

这里内容主要参考于开发 Linux 命令行实用程序,详情可参见文章。

1.selpg 定义

selpg 是从文本输入选择页范围的实用程序。该输入可以来自作为最后一个命令行参数指定的文件,在没有给出文件名参数时也可以来自标准输入

2.参数处理

“-sNumber”和“-eNumber”强制选项:
selpg 要求用户用两个命令行参数“-sNumber”和“-eNumber”指定要抽取的页面范围的起始页和结束页,它们必须是命令行上在命令名 selpg 之后的头两个参数。selpg会对所给的页号进行合理性检查。即它会检查两个数字是否为有效的正整数以及结束页是否不小于起始页。

$ selpg -s10 -e20 ...
代表从第 10 页开始,在第 20 页结束。

“-lNumber”和“-f”可选选项:

“-lNumber”定义页的固定长度和页由页行数定界,“-f”该类型文本的页由 ASCII 换页字符(十进制数值为 12,在 C 中用“\f”表示)定界。“-lNumber”和“-f”选项是互斥的,它们不能共同存在。它们是缺省类型,因此不必给出选项进行说明。也就是说,如果既没有给出“-lNumber”也没有给出“-f”选项,则 selpg 会理解为页有固定的长度。

$ selpg -s10 -e20 -l66 ...
代表页有固定长度,每页为 66 行

$ selpg -s10 -e20 -f ...
该命令告诉 selpg 在输入中寻找换页符,并将其作为页定界符处理。

“-dDestination”可选选项:
selpg 还允许用户使用“-dDestination”选项将选定的页直接发送至打印机。这里,“Destination”应该是 lp 命令“-d”选项可接受的打印目的地名称。

selpg -s10 -e20 -dlp1
该命令将选定的页作为打印作业发送至 lp1 打印目的地。

3.代码实现

实现的代码地址:https://github.com/wutao123456789/Homework
此次代码的实现主要依据在开发 Linux 命令行实用程序中给出的selpg.c文件编写。

  • 使用库
import (
   "bufio"
   "fmt"
   "io"
   "os"
   "os/exec"
   "github.com/spf13/pflag"
)

其中pflag使用的是github上的公开库,需要首先下载到本地,具体的安装方法请点击。

  • selpg_args结构
type selpg_args struct {
	start_page  int
	end_page    int
	in_filename string
	dest        string
	page_len    int
	page_type   int
}
  • 全局变量
var progname string			//程序名

const INT_MAX = int(^uint(0) >> 1)  //将所有位数取0,再取反,最后右移一位。如:0000 取反  1111  后移一位 0111
  • process_args()函数
func (arg *selpg_args)process_args() {

	progname = os.Args[0]

	pflag.IntVarP(&arg.start_page, "start_page", "s", 0, "start page")
	pflag.IntVarP(&arg.end_page, "end_page", "e", 0, "end page")
	pflag.IntVarP(&arg.page_type, "page_type", "f", 0, "Page type")
	pflag.IntVarP(&arg.page_len, "page_len", "l", 36, "page len")
	pflag.StringVarP(&arg.dest, "dest", "d", "", "dest")

	pflag.Parse()
	file_arr := pflag.Args()
	arg.in_filename =""

	count := 0
	for{
		if arg.in_filename =="" && file_arr[count] != "<"{
			arg.in_filename = file_arr[count]
		}
		if file_arr[count] == ">"|| file_arr[count] == "|"{
			count++
			arg.dest = file_arr[count]
		}
		count++
		if count >= len(file_arr){
			break
		}
	}

	if len(os.Args) < 3 {
		fmt.Fprintf(os.Stderr, "%s: please input enough arguments\n", progname)
		usage()
		os.Exit(1)
	}
	if arg.start_page < 1 || arg.start_page > INT_MAX {
		fmt.Fprintf(os.Stderr, "%s: please input positive integer for start_page\n", progname)
		usage()
		os.Exit(2)
	}
	if arg.end_page < 1 || arg.end_page > (INT_MAX-1) || arg.end_page < arg.start_page {
		fmt.Fprintf(os.Stderr, "%s: please input positive integer for end_page or start_page should not be greater than end_page\n", progname)
		usage()
		os.Exit(3)
	}
	if arg.page_len < 1 || arg.page_len > (INT_MAX-1) {
		fmt.Fprintf(os.Stderr, "%s: please input positive integer for page_len\n", progname)
		pflag.Usage()
		os.Exit(4)
	}
}

进行参数的绑定,使得数据结构arg能够获取输入参数的值,并通过pflag.Args()获取非参数的值。并进行合理性判断,确保输入了强制性参数和输入值的有效性。

  • process_input()函数
func (arg selpg_args)process_input() {

	var read *bufio.Reader
	var write *bufio.Writer

	if arg.in_filename == "" {
		read = bufio.NewReader(os.Stdin)
	} else {
		fin, err := os.Open(arg.in_filename)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s: could not open input file %s\n", progname, arg.in_filename)
			os.Exit(5)
		}
		read = bufio.NewReader(fin)
		defer fin.Close()
	}

	if arg.dest == "" {
		write = bufio.NewWriter(os.Stdout)
	} else {
		fin1, err := os.Open(arg.dest)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s: could not open output file %s\n", progname, arg.dest)
			os.Exit(6)
		}
		write = bufio.NewWriter(fin1)
		defer fin1.Close()
	}

	line_number, page_number, pLen := 1, 1, arg.page_len
	judge_Flag := '\n'
	if arg.page_type==1 {
		judge_Flag = '\f'
		pLen = 1
	}

	for {
		line,err:= read.ReadString(byte(judge_Flag));
		if err != nil && len(line) == 0 {
			break
		}
		if line_number > pLen {
			page_number++
			line_number = 1
		}
		if page_number >= arg.start_page && page_number <= arg.end_page {
			write.Write([]byte(line))
		}
		line_number++
	}

	if page_number < arg.end_page {
		fmt.Fprintf(os.Stderr,
			"\n%s: put exist error\n", progname)
	}
}

首先判断从那读取数据,是命令行还是文件。然后判断是将数据输出到屏幕上还是输出到文件当中。确定页的界定符,如果按行数则获取限定每页的行数;如果根据’\f’判断,则出现一次为一页。最后根据当前页数与计划的结束页数对比判断输出是否成功。

4.测试样例

由于使用的为goland进行测试,所以是通过编译输入参数来实现测试。
在这里插入图片描述

  • $ selpg -s1 -e1 input.txt
    在这里插入图片描述
    默认的每页行数为36。

-$ selpg -s1 -e1 < input.txt

在这里插入图片描述
结果一致

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ui5 cli是SAPUI5的命令行工具,它提供了一组命令和功能,以帮助开发人员在开发、测试和部署SAPUI5应用程序时更高效地工作。 首先,ui5 cli提供了项目创建和初始化的命令。使用ui5 init命令可以创建一个新的SAPUI5项目,并在项目中生成基本的目录结构和文件。此外,ui5 cli还支持从GitHub或SAP的代码示例仓库中初始化项目,以便快速开始开发。 其次,ui5 cli还提供了开发服务器和实时刷新的功能。使用ui5 serve命令,开发人员可以启动一个本地开发服务器,用于快速测试和调试应用程序。该服务器会监视文件的更改,并自动重新加载应用程序,从而提供实时刷新的体验。 ui5 cli还提供了构建和打包应用程序的能力。使用ui5 build命令,开发人员可以将应用程序构建为一个或多个可部署的包。构建过程中,ui5 cli会执行代码压缩、文件合并和资源优化等操作,以优化应用程序的性能和加载速度。 此外,ui5 cli还包含了一系列工具和插件,以帮助开发人员更好地管理和测试SAPUI5应用程序。例如,ui5命令用于执行一些常见的开发任务,如代码检查、单元测试和模板生成。ui5 deploy命令可用于将构建好的应用程序部署到远程服务器或云平台。 总之,ui5 cli是一个强大的命令行工具,提供了丰富的功能和灵活的命令,可以显著提高SAPUI5应用程序开发效率和质量。无论是在本地开发环境中还是在生产环境中,ui5 cli都是SAPUI5开发人员的关键工具之一。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值