1. 实验要求
使用 golang 开发 开发 Linux 命令行实用程序 中的 selpg
2. 实验步骤
开发Linux命令行实用程序
安装pflag
在终端输入以下命令
go get github.com/spf13/pflag #install到本地
go test github.com/spf13/pflag #test
import flag "github.com/spf13/pflag" #导入,可以继续使用flag
参数处理
输入以下代码,并保存为test.go
package main
import (
"fmt"
flag "github.com/spf13/pflag"
)
func main() {
var s int
flag.IntVarP(&s, "start", "s", 0, "startPage")
flag.Parse()
fmt.Printf("%d\n", s)
}
将终端工作路径切换到当前工作目录下
$ go build test.go
$ ./test
0
$ ./test -s10
10
$ ./test -s20
20
$ ./test --start=30
30
结合终端输出的结果,分析以下test.go代码。
flag.IntVarP定义命令行参数
&s——将命令行参数的值绑定到s变量上
“start”——可以通过- -start=30为参数赋值
“s“——可以通过-s10为参数赋值
最后要通过flag.Parse解析
2.1 项目所涉及的Go语言知识点
做这次作业需要使用的Go语言的知识点大概有以下几个方面
① 函数
② 结构体
③ 参数的绑定
④ 异常处理
⑤ 文件读写
⑥ 命令行参数的解析
函数介绍
func getArgs(args *Args) :定义命令行参数
func checkArgs(args *Args): 检查参数的合法性
func getReader(args *Args) *bufio.Reader:获取bufio.Reader对象
func execution(args *Args):执行文件读入写出
func readByL(args *Args, reader *bufio.Reader, writer *bufio.Writer):按行读入,并输出到标准输出
func readByF(args *Args, reader *bufio.Reader, writer *bufio.Writer) :按页读入,并输出到标准输出
func readByLWithD(args *Args, reader *bufio.Reader, writer io.WriteCloser) :按行读入,并由管道输出到"-dXXX"
func readByFWithD(args *Args, reader *bufio.Reader, writer io.WriteCloser) :按页读入,并由管道输出到"-dXXX"
2.2 理解selpg
selpg 是一个自定义命令行程序,全称select page,即从源(标准输入流或文件)读取指定页数的内容到目的地(标准输出流或给给打印机打印)
2.3 Go使用flag包解释命令行参数
flag包能解析的参数有如下四种形式,使用的时候分三种类型:
类型一
cmd -flag=x // 支持所有类型
cmd -flag x // 只支持非bool类型
类型二
cmd -flag // 只支持bool类型
类型三
cmd abc // 没有flag的参数
2.3.1 类型一
类型一定义参数有两种形式,下方Xxx代表类型
2.3.1.1 类型一定义参数
flag.Xxx()
flag.String(), Bool(), Int() 这种形式返回一个指向该参数的指针
例子
var date = flag.Int("d", 20171107, "help message for date")
flag.Parse()
(注意: date 是指向 -d 参数值的指针)
若在命令行输入 -d=20121212 -a=20 或者 -d 20121212 -a 20,则我们在程序中即可用 *date 取得 -d 的值20121212
若只输入 -a=20 或者 -a 20,因为缺省标志 -d ,则 *date 取到的是 -d 定义中的默认值 20171107
flag.XxxVar()
flag.StringVar(), BoolVar(), IntVar() 这种形式把参数绑定到一个变量
例子
var age int
flag.IntVar(&age, "a", 18, "help message for age")
flag.Parse()
命令行输入-d=20121212 -a=20 或者-d=20121212 -a 20 ,在程序里 变量age 则获取到 -a 的值 20
若只输入-d=20121212 或者-d=20121212,缺省标志-a, 则 变量age 获取定义中的默认值 18
2.3.1.2 类型一解析参数
注意到上面例子最后都带有一行 flag.Parse()
因为定义好参数后,只有调用方法 flag.Parse() 解析命令行参数到定义的flag,这样我们才能使用上面两个例子的 *date 和 age 取得对应flag的参数值
2.3.2 类型二
cmd -flag //该形式只支持bool类型,对应的值是1, 0, t, f, true, false, TRUE, FALSE, True, False
默认的,如果我们在命令行里提供了-flag,则其对应的值为true,否则为flag.Bool/BoolVar中指定的默认值;如果希望显示设置为false则使用-flag=false。
例子
var exist_f = flag.Bool("f", false, "help message for format")
flag.Parse()
当在命令行输入 -d=123 -f 时,程序里 *exist_f 的值就为 true 了
若命令行只输入 -d=123 时,因为缺省-f,*exist_f 的值为事先定义中默认的 false
2.3.3 类型三
cmd abc //没有flag的参数
1.通过 flag.Args() 获取非flag参数列表
2.通过 flag.Arg(i) 来获取非flag命令行第i个参数,i 从 0 开始
3.通过flag.NArg() 获得非flag参数个数
例子
当命令行敲入 -d 20121212 -a 20 Wang yx ,最后两个值即为不带标志的参数
flag.Parse()
var fullName = flag.Args() // fullName = ['Wang', 'yx']
var firstName = flag.Arg(0) // firstName = Wang
var lastName = flag.Arg(1) // lastName = yx
var num = flag.NArg() // num = 2
2.4 命令行参数设计
selpg -s startPage -e endPage [-l linePerPage | -f ][-d dest] filename
必需标志以及参数:
-s,后面接开始读取的页号 int
-e,后面接结束读取的页号 int
s和e都要大于1,并且s <= e,否则提示错误
可选参数:
-l,后面跟行数 int,代表多少行分为一页,不指定 -l 又缺少 -f 则默认按照72行分一页
-f,该标志无参数,代表按照分页符’\f’ 分页
-d,后面接打印机标号,用于将内容传送给打印机打印 我没有打印机用于测试,所以当使用 -d destination(随便一个字符串作参数)时,就会通过管道把内容发送给 grep命令,并把grep处理结果显示到屏幕
filename,唯一一个无标识参数,代表选择读取的文件名
[] 中内容为可选择性输入的
2.5 读写函数
官网解释:bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象。
2.5.1 bufio.NewReader
os.Stdlin和打开文件都能得到输入数据流,而bufio.NewReader就是一个对象,该对象带有一个缓冲区,与一个数据流绑定。
通过
rd := bufio.NewReader(fin)
if psa.page_type == false {
line_ctr = 0
page_ctr = 1
for true {
line, err2 = rd.ReadString('\n')
if err2 != nil { /* error or EOF */
break
}
line_ctr++
if line_ctr > psa.page_len {
page_ctr++
line_ctr = 1
}
if page_ctr >= psa.start_page && page_ctr <= psa.end_page {
fmt.Fprintf(fout, "%s", line)
}
}
}
创建一个newreader,是bufio.newReader类型,它绑定了一个文件流,用bufio.NewReader对象的好处是我们可以利用这个对象的函数方法,如
line, err := reader.ReadBytes('\n')
这样就能按行读取缓冲区中的数据。
2.5.2 bufio.Writer
这个对象和bufio.Reader很像,不过它是绑定了一个输出数据流。 可以利用
writer := bufio.NewWriter(os.Stdout)
errW := writer.Write(byte[]("line 1"))
导出到标准输出,同样也可以绑定到文件数据流中
2.6 os/exe
exec包执行外部命令。它包装了os.StartProcess函数以便更容易的修正输入和输出,使用管道连接I/O,以及作其它的一些调整。
这个包可以帮助我们在程序中启动子进程并使用管道连接I/0。具体用法是先建立一个子进程的输入管道,启动子进程,从父进程接收标准输出,关闭管道,关闭子进程。
2.6.1 exec.Command(filePath)
cmd_grep := exec.Command("./" + args.printDestination)
创建一个命令对象,参数为子进程路径和子进程参数(可选)
2.6.2 func (c *Cmd) StdinPipe() (io.WriteCloser, error)
它构建了到子进程的输入管道,返回一个io.WriterClose对象,这个对象绑定了一个数据流,该数据流是子进程的数据输入流。所以可以直接调用对象的方法writer.Write([]byte)将数据转化为到子进程的标准输入,如:
_, errW := writer.Write([]byte("line 3"))
2.6.3 func (c *Cmd) Start() error
启动子进程
2.6.4 func (*Cmd) Wait
在命令执行完成后调用,返回所调用命令的执行情况,同时释放资源
3. 代码设计
大体框架是:
① 读取命令行参数
② 打开需要处理的文件
③ 根据用户给定参数进行操作
④ 结束读写
3.1 引入所需要的包
import (
"fmt"
"os"
"bufio"
"github.com/spf13/pflag"
"os/exec"
"io"
)
注:由于这里老师要求要使用Unix标准,所以引入pflag包代替flag,但是两个包的函数在使用上面基本是相同的。
3.2 创立记录数据的结构体
type selpg_args struct {
start_page int //开始页码
end_page int //结束页码
in_filename string // 文件名
page_len int // 每一页的大小
page_type bool // 页类型
print_dest string // 打印地
}
3.3 main 函数
func main() {
//创建结构体数据
sa := selpg_args{0, 0, "", 5, false, ""}
//拿到生成的可执行文件的名字
progname = os.Args[0]
//初始化结构体数据
Parser(&sa)
//处理参数
processArgs(len(os.Args), &sa)
//传递参数,完成对应操作
processInput(&sa)
}
3.4 Parser函数
func Parser(p *selpg_args) {
pflag.Usage = usage
pflag.IntVarP(&p.start_page,"start", "s", 0, "首页")
pflag.IntVarP(&p.end_page,"end","e", 0, "尾页")
pflag.IntVarP(&p.page_len,"linenum", "l", 5, "打印的每页行数")
pflag.BoolVarP(&p.page_type,"printdes","f", false, "是否用换页符换页")
pflag.StringVarP(&p.print_dest, "othertype","d", "", "打印目的地")
pflag.Parse()
}
注:这里使用pflag包的函数,完成对命令行数据的操作。
3.5 processArgs函数
processArgs函数主要是用于处理输入时候的各种错误,比如起始页码是负数,终止页码小于起始页码等情况,增加程序的健壮性,这里给出部分情况。
func processArgs(psa *selpg_args) {
//处理-s 这种情况
if os.Args[1][0] != '-' || os.Args[1][1] != 's' {
fmt.Fprintf(os.Stderr, "%s: 1st arg should be -s=start_page\n", progname)
pflag.Usage()
os.Exit(2)
}
//处理起始的页码小于1的情况
if psa.start_page < 1 {
fmt.Fprintf(os.Stderr, "%s: invalid start page %s\n", progname, psa.start_page)
pflag.Usage()
os.Exit(3)
}
....
....
//检查要操作的文件是否存在
if pflag.NArg() > 0 {
psa.in_filename = pflag.Arg(0)
/* check if file exists */
file, err := os.Open(psa.in_filename)
if err != nil {
fmt.Fprintf(os.Stderr, "%s: input file \"%s\" does not exist\n", progname, psa.in_filename)
os.Exit(7)
}
/* check if file is readable */
file, err = os.OpenFile(psa.in_filename, os.O_RDONLY, 0666)
if err != nil {
if os.IsPermission(err) {
fmt.Fprintf(os.Stderr, "%s: input file \"%s\" exists but cannot be read\n", progname, psa.in_filename)
os.Exit(8)
}
}
file.Close()
}
3.6 processInput函数
processInput函数用来对文件的内容进行处理,根据后缀参数的类型完成操作,这里只给出函数的一部分。
func processInput(psa *selpg_args) {
fin := os.Stdin
fout := os.Stdout
var (
page_ctr int
line_ctr int
err error
err1 error
err2 error
line string
cmd *exec.Cmd
stdin io.WriteCloser
)
4. 程序测试
可使用的 selpg
命令字符串示例:
下面的测试结果是两次的,上面的是test.go文件,下面的是wrong.go文件,对比两次的测试结果,有区别之处做了对比
-
1
$ selpg -s1 -e1 input_file
该命令将把“input_file”的第 1 页写至标准输出(也就是屏幕),因为这里没有重定向或管道。
[ailsa@localhost spf13]$ ./selpg -s1 -e2 -f test.go
package main
import (
"fmt"
flag "github.com/spf13/pflag"
)
func main() {
var s int
flag.IntVarP(&s, "start", "s", 0, "startPage")
flag.Parse()
fmt.Printf("%d\n", s)
}
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
-
1
$ selpg -s1 -e1 < input_file
该命令与示例 1 所做的工作相同,但在本例中,selpg 读取标准输入,而标准输入已被 shell/内核重定向为来自“input_file”而不是显式命名的文件名参数。输入的第 1 页被写至屏幕。
[ailsa@localhost spf13]$ ./selpg -s1 -e1 < input_file.txt
./selpg: done
-
1
$ other_command | selpg -s10 -e20
“other_command”的标准输出被 shell/内核重定向至 selpg 的标准输入。将第 10 页到第 20 页写至 selpg 的标准输出(屏幕)。
ls | ./selpg -s1 -e2命令这里的test.go与wrong.go两次的结果不同
[ailsa@localhost spf13]$ ls | ./selpg -s10 -e20
./selpg: start_page (10) greater than total pages (1), no output written
./selpg: done
[root@localhost spf13]# ./selpg -s1 -e1 < input_file.txt
./selpg: done
[root@localhost spf13]# ls | ./selpg -s1 -e2
error_file.txt
input_file.go
input_file.txt
output_file.txt
pflag
pflag.a
selpg
selpg.c
test
test.go
wrong.go
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
-
1
$ selpg -s10 -e20 input_file >output_file
selpg 将第 10 页到第 20 页写至标准输出;标准输出被 shell/内核重定向至“output_file”。
[ailsa@localhost spf13]$ ./selpg -s10 -e20 input_file.txt output_file.txt
./selpg: start_page (10) greater than total pages (1), no output written
./selpg: done
-
1
$ selpg -s10 -e20 input_file 2>error_file
selpg 将第 10 页到第 20 页写至标准输出(屏幕);所有的错误消息被 shell/内核重定向至“error_file”。请注意:在“2”和“>”之间不能有空格;这是 shell 语法的一部分(请参阅“man bash”或“man sh”)。
这里对比了两次的输出,但是test.go时的error忘了截图,按理说应该是空的没有输出,下面的wrong.go文件输出了内容:
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
[ailsa@localhost spf13]$ sudo ./selpg -s1 -e2 input_file.txt 2>error_file.txt
bash: error_file.txt: Permission denied
[ailsa@localhost spf13]$ su
Password:
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt 2>error_file.txt
[root@localhost spf13]#
root@localhost spf13]# ./selpg -s10 -e20 input_file.txt output_file.txt
./selpg: start_page (10) greater than total pages (1), no output written
./selpg: done
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt 2>error_file.txt
[root@localhost spf13]# cat error_file.txt
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
-
1
$ selpg -s10 -e20 input_file >output_file 2>error_file
selpg 将第 10 页到第 20 页写至标准输出,标准输出被重定向至“output_file”;selpg 写至标准错误的所有内容都被重定向至“error_file”。当“input_file”很大时可使用这种调用;您不会想坐在那里等着 selpg 完成工作,并且您希望对输出和错误都进行保存。
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt>output_file.txt 2>error_file.txt
[root@localhost spf13]#
-
1
$ selpg -s10 -e20 input_file >output_file 2>/dev/null
selpg 将第 10 页到第 20 页写至标准输出,标准输出被重定向至“output_file”;selpg 写至标准错误的所有内容都被重定向至 /dev/null(空设备),这意味着错误消息被丢弃了。设备文件 /dev/null 废弃所有写至它的输出,当从该设备文件读取时,会立即返回 EOF。
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt>output_file.txt 2>/dev/null
[root@localhost spf13]#
-
1
$ selpg -s10 -e20 input_file >/dev/null
selpg 将第 10 页到第 20 页写至标准输出,标准输出被丢弃;错误消息在屏幕出现。这可作为测试 selpg 的用途,此时您也许只想(对一些测试情况)检查错误消息,而不想看到正常输出。
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt>/dev/null
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
[root@localhost spf13]#
-
1
$ selpg -s10 -e20 input_file | other_command
selpg 的标准输出透明地被 shell/内核重定向,成为“other_command”的标准输入,第 10 页到第 20 页被写至该标准输入。“other_command”的示例可以是 lp,它使输出在系统缺省打印机上打印。“other_command”的示例也可以 wc,它会显示选定范围的页中包含的行数、字数和字符数。“other_command”可以是任何其它能从其标准输入读取的命令。错误消息仍在屏幕显示。
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt | ls
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
error_file.txt input_file.txt pflag selpg test
input_file.go output_file.txt pflag.a selpg.c test.go
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt | cat test.go
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
package main
import (
"fmt"
flag "github.com/spf13/pflag"
)
func main() {
var s int
flag.IntVarP(&s, "start", "s", 0, "startPage")
flag.Parse()
fmt.Printf("%d\n", s)
}
[root@localhost spf13]#
-
1
$ selpg -s10 -e20 input_file 2>error_file | other_command
与上面的示例 9 相似,只有一点不同:错误消息被写至“error_file”。
[root@localhost spf13]# ls
error_file.txt input_file.txt pflag selpg test
input_file.go output_file.txt pflag.a selpg.c test.go
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt>error_file.txt | ls
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
error_file.txt input_file.txt pflag selpg test
input_file.go output_file.txt pflag.a selpg.c test.go
[root@localhost spf13]#
下面的是test.go的测试截图:
[ailsa@localhost spf13]$ ls
input_file.go pflag pflag.a selpg selpg.c test test.go
[ailsa@localhost spf13]$ go test pflag
can't load package: package pflag: cannot find package "pflag" in any of:
/usr/lib/golang/src/pflag (from $GOROOT)
/home/ailsa/gowork/src/pflag (from $GOPATH)
[ailsa@localhost spf13]$ cp pflag /usr/lib/golang/src/
cp: omitting directory ‘pflag’
[ailsa@localhost spf13]$ cp pflag /usr/lib/golang/src/ -rf
cp: cannot create directory ‘/usr/lib/golang/src/pflag’: Permission denied
[ailsa@localhost spf13]$ sudo cp pflag /usr/lib/golang/src/ -rf
[ailsa@localhost spf13]$ sudo cp pflag /home/ailsa/gowork/src/pflag -rf
[ailsa@localhost spf13]$ selpg
bash: selpg: command not found...
[ailsa@localhost spf13]$ ./selpg
./selpg: not enough arguments
USAGE: ./selpg -sstart_page -eend_page [ -f | -llines_per_page ] [ -ddest ] [ in_filename ]
[ailsa@localhost spf13]$ ./selpg -s 1 -e 10 -f
./selpg: invalid start page
USAGE: ./selpg -sstart_page -eend_page [ -f | -llines_per_page ] [ -ddest ] [ in_filename ]
[ailsa@localhost spf13]$ ls
input_file.go pflag pflag.a selpg selpg.c test test.go
[ailsa@localhost spf13]$ ./selpg -s 1 -e 10 -f test.go
./selpg: invalid start page
USAGE: ./selpg -sstart_page -eend_page [ -f | -llines_per_page ] [ -ddest ] [ in_filename ]
[ailsa@localhost spf13]$ ./selpg 1 2
./selpg: 1st arg should be -sstart_page
USAGE: ./selpg -sstart_page -eend_page [ -f | -llines_per_page ] [ -ddest ] [ in_filename ]
[ailsa@localhost spf13]$ ./selpg -s 1 -e 2 -f test.go
./selpg: invalid start page
USAGE: ./selpg -sstart_page -eend_page [ -f | -llines_per_page ] [ -ddest ] [ in_filename ]
[ailsa@localhost spf13]$ ./selpg -s1 -e2 -f test.go
package main
import (
"fmt"
flag "github.com/spf13/pflag"
)
func main() {
var s int
flag.IntVarP(&s, "start", "s", 0, "startPage")
flag.Parse()
fmt.Printf("%d\n", s)
}
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
[ailsa@localhost spf13]$
下面的是wrong.go的测试截图:
import (
//"fmt"
//flag "github.com/spf13/pflag"
)
func main() {
var s int
flag.IntVarP(&s, "start", "s", 0, "startPage")
flag.Parse()
fmt.Printf("%d\n", s)
}
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt>error_file.txt | ls
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
error_file.txt input_file.txt pflag selpg test wrong.go
input_file.go output_file.txt pflag.a selpg.c test.go
[root@localhost spf13]# ls
error_file.txt input_file.txt pflag selpg test wrong.go
input_file.go output_file.txt pflag.a selpg.c test.go
[root@localhost spf13]# cat error_file.txt
[root@localhost spf13]# ./selpg -s1 -e2 -f wrong.go
package main
import (
//"fmt"
//flag "github.com/spf13/pflag"
)
func main() {
var s int
flag.IntVarP(&s, "start", "s", 0, "startPage")
flag.Parse()
fmt.Printf("%d\n", s)
}
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
[root@localhost spf13]# clear
[root@localhost spf13]# ./selpg -s1 -e2 -f wrong.go
package main
import (
//"fmt"
//flag "github.com/spf13/pflag"
)
func main() {
var s int
flag.IntVarP(&s, "start", "s", 0, "startPage")
flag.Parse()
fmt.Printf("%d\n", s)
}
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
[root@localhost spf13]# ./selpg -s1 -e1 < input_file.txt
./selpg: done
[root@localhost spf13]# ls | ./selpg -s1 -e2
error_file.txt
input_file.go
input_file.txt
output_file.txt
pflag
pflag.a
selpg
selpg.c
test
test.go
wrong.go
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
[root@localhost spf13]# ./selpg -s10 -e20 input_file.txt output_file.txt
./selpg: start_page (10) greater than total pages (1), no output written
./selpg: done
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt 2>error_file.txt
[root@localhost spf13]# cat error_file.txt
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
[root@localhost spf13]# gedit error_file.txt
(gedit:31849): GLib-GIO-CRITICAL **: 22:41:51.010: g_dbus_proxy_new_sync: assertion 'G_IS_DBUS_CONNECTION (connection)' failed
(gedit:31849): dconf-WARNING **: 22:41:51.018: failed to commit changes to dconf: The connection is closed
(gedit:31849): dconf-WARNING **: 22:41:51.025: failed to commit changes to dconf: The connection is closed
Error creating proxy: The connection is closed (g-io-error-quark, 18)
Error creating proxy: The connection is closed (g-io-error-quark, 18)
Error creating proxy: The connection is closed (g-io-error-quark, 18)
Error creating proxy: The connection is closed (g-io-error-quark, 18)
Error creating proxy: The connection is closed (g-io-error-quark, 18)
(gedit:31849): dconf-WARNING **: 22:41:51.206: failed to commit changes to dconf: The connection is closed
(gedit:31849): dconf-WARNING **: 22:41:51.206: failed to commit changes to dconf: The connection is closed
(gedit:31849): dconf-WARNING **: 22:41:51.207: failed to commit changes to dconf: The connection is closed
(gedit:31849): dconf-WARNING **: 22:42:17.454: failed to commit changes to dconf: The connection is closed
** (gedit:31849): WARNING **: 22:42:17.543: Set document metadata failed: Setting attribute metadata::gedit-position not supported
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt 2>error_file.txt./selpg -s1 -e2 input_file.txt>output_file.txt 2>error_file.txt
bash: error_file.txt./selpg: No such file or directory
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt>output_file.txt 2>error_file.txt
[root@localhost spf13]# ls
error_file.txt input_file.txt pflag selpg test wrong.go
input_file.go output_file.txt pflag.a selpg.c test.go
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt>output_file.txt 2>error_file.txt
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt>output_file.txt 2>/dev/null
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt>/dev/null
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt | ls
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
error_file.txt input_file.txt pflag selpg test wrong.go
input_file.go output_file.txt pflag.a selpg.c test.go
[root@localhost spf13]# ./selpg -s1 -e2 input_file.txt | cat wrong.go
./selpg: end_page (2) greater than total pages (1), less output than expected
./selpg: done
package main
import (
//"fmt"
//flag "github.com/spf13/pflag"
)
func main() {
var s int
flag.IntVarP(&s, "start", "s", 0, "startPage")
flag.Parse()
fmt.Printf("%d\n", s)
}
遇到的问题
5 遇到的问题
最大的问题是selpg安装不上去,虚拟机老是死机,pflag获取不到,花了很长时间,配置路径,下载了selpg.c 然后gcc selpg.c -o selpg生成了可执行文件,直接在github上下载压缩解压copy到安装路径和缺包的两个bin目录下selpg终于能使用了,只是不是和文档里面一样的用法,是用了./selpg 。然后就是最开始读文档一头雾水,所以看了很多博客,好像大家都没有遇到我这样的问题,上次配置golang环境也是这样,修改路径还是找不到包最后也是手动copy到bin下面才能用的,这次吃一堑长一智,下次不能再花时间在这个问题上了。虚拟机奔溃的原因暂时还找不到,一打开命令窗口和谷歌浏览器就死机,只能强制关机重启虚拟机,反复好几次简直奔溃,所以又捣鼓了好久主机,考虑如果下次再死机就重装系统试一下了。