Go中如何将io.Writer转换成字符串(将两个管道连接的exec.Command输出的标准输出获取成字符串)

假设我们需要在Go中运行下面的命令:

PS -A | grep wget

这里需要写成两个exec.Command,如下,第一个命令为cmd,第二个为cmd2

go 复制代码
cmd := exec.Command("PS", "-A")
cmd2 := exec.Command("grep", "wget")

然后使用管道连接二者的标准输出和标准输入,需要注意第一个命令cmd的标准输出应该使用cmd.StdoutPipe(),而不是Stdout,如下(忽略了错误err和其处理):

go 复制代码
cmd2.Stdin, _ = cmd.StdoutPipe()

因为cmd.Stdout是一个io.Writer,是一个写入器,因为这个输出是要写入某些地方的。而同理,cmd2.Stdin是一个io.Reader,是一个读取器,用来读取一些地方的内容。二者直接赋值的话会出现类型不匹配的错误。所以需要使用StdoutPipe()函数,这个函数会返回一个io.Reader。(这里比较绕,所以可能需要想一下)

在获取了输出之后,需要将其转换成字符串的话,可以使用bytes.Buffer来获取cmd2.Stdout的标准输出(记住这是个io.Writer),然后再转换成字符串。

我们是是无法直接将io.Writer直接写入到bytes.Buffer之中的,你可能会说bytes.Buffer不是有两个方法ReadFromWriteTo吗?

前者只能读取io.Reader的,后者只能写入io.Writer,所以我们需要一个管道来将io.Writer转换成io.Reader,然后才能读取或复制其内容。而这个转换就是再使用一次管道,如下:

go 复制代码
var buf bytes.Buffer
r, w, _ := os.Pipe()
cmd2.Stdout = w
go buf.ReadFrom(r)

这里buf.ReadFrom(r)必须使用 goroutine,也就是让这个代码并行运行,所以在前面加上go

这里的go buf.ReadFrom(r)也可以使用go io.Copy(&buf, r)替代,效果一样。

因为命令执行的顺序是先启动cmd2,然后运行cmdcmd运行完之后,数据流通过管道传递给cmd2cmd2再运行。不然cmd运行的时候的标准输出是空的,就会一直等。

buf.ReadFrom(r)cmd2也是同理,不过由于这是行代码,无法使用start启动它,所以并行就行了。

接下来的命令如下:

go 复制代码
cmd2.Start()
cmd.Run()
cmd2.Wait()

这里就是前面说的流程:cmd2启动,运行cmd,让cmd2等待cmd的输出。

需要注意一点:go buf.ReadFrom(r)其实可以放在上面代码中,除了最后一行之外的任何地方。之所以不能放在最后是因为这时候都运行完了,再读取就是空的了。

然后将其转换成字符串:

go 复制代码
str := buf.String()

打印看看:

go 复制代码
fmt.Println("123" + str + "123")

之所以要前后都加上"123"是为了避免调试的时候把输出到标准输出文件的内容当成这里打印的。

结果如下:

% go run main.go
12360651 ttys010    0:00.00 grep wget
123

这里分成两行是因为获取的时候grep wget后面有个\n,这里看不出来,如果%#v格式化打印就能看到了。

完整代码如下:

func main() {
	cmd := exec.Command("PS", "-A")
	cmd2 := exec.Command("grep", "wget")
	cmd2.Stdin, _ = cmd.StdoutPipe()
	var buf bytes.Buffer
	r, w, _ := os.Pipe()
	cmd2.Stdout = w
	// 下面这行代码可以替换为:go io.Copy(&buf, r)
	go buf.ReadFrom(r)
	cmd2.Start()
	cmd.Run()
	cmd2.Wait()
	str := buf.String()
	fmt.Println("123" + str + "123")
}

希望能帮到有需要的人~

相关推荐
疯狂的程需猿34 分钟前
一个百度、必应搜索引擎图片获取下载的工具包
golang·图搜索
明月看潮生2 小时前
青少年编程与数学 02-003 Go语言网络编程 09课题、Cookie
青少年编程·golang·网络编程·编程与数学
明月看潮生3 小时前
青少年编程与数学 02-003 Go语言网络编程 15课题、Go语言URL编程
开发语言·网络·青少年编程·golang·编程与数学
明月看潮生3 小时前
青少年编程与数学 02-003 Go语言网络编程 14课题、Go语言Udp编程
青少年编程·golang·网络编程·编程与数学
hlsd#4 小时前
go 集成go-redis 缓存操作
redis·缓存·golang
qq_1728055918 小时前
GIN 反向代理功能
后端·golang·go
__AtYou__18 小时前
Golang | Leetcode Golang题解之第535题TinyURL的加密与解密
leetcode·golang·题解
kevin_tech1 天前
Go API 多种响应的规范化处理和简化策略
开发语言·后端·golang·状态模式
幺零九零零1 天前
【Golang】sql.Null* 类型使用(处理空值和零值)
数据库·sql·golang
cookies_s_s1 天前
Golang--DOS命令、变量、基本数据类型、标识符
golang