概述

unix/linux OS 的一个进程的输出可以是另一个进程的输入,这些进程使用stdin与stdout设备作为通道,在进程之间传递数据。

同样的,GO中有io.Reader与io.Writer两个接口,如果要对一个设备进行读/写,调用实现了这两个接口的方法即可。

GO对管道的支持

  1. func t1() {
  2. cmd0 := exec.Command("echo","-n","how are you")
  3. fmt.Println(cmd0)
  4. }

exec.Command返回的对象的几个主要方法:

  1. // Stdin specifies the process's standard input.
  2. //
  3. // If Stdin is nil, the process reads from the null device (os.DevNull).
  4. //
  5. // If Stdin is an *os.File, the process's standard input is connected
  6. // directly to that file.
  7. //
  8. // Otherwise, during the execution of the command a separate
  9. // goroutine reads from Stdin and delivers that data to the command
  10. // over a pipe. In this case, Wait does not complete until the goroutine
  11. // stops copying, either because it has reached the end of Stdin
  12. // (EOF or a read error) or because writing to the pipe returned an error.
  13. Stdin io.Reader
  14.  
  15. // Stdout and Stderr specify the process's standard output and error.
  16. //
  17. // If either is nil, Run connects the corresponding file descriptor
  18. // to the null device (os.DevNull).
  19. //
  20. // If either is an *os.File, the corresponding output from the process
  21. // is connected directly to that file.
  22. //
  23. // Otherwise, during the execution of the command a separate goroutine
  24. // reads from the process over a pipe and delivers that data to the
  25. // corresponding Writer. In this case, Wait does not complete until the
  26. // goroutine reaches EOF or encounters an error.
  27. //
  28. // If Stdout and Stderr are the same writer, and have a type that can
  29. // be compared with ==, at most one goroutine at a time will call Write.
  30. Stdout io.Writer
  31. Stderr io.Writer

示例

  1. /*
  2. 参数传入的是命令组
  3. 通过buffer一次次读取返回结果,不怕返回的数据量大
  4. 如果命令是shell那样有|管道符,则使用Pip方法即可
  5. */
  6. func PipCmd(cmd []string,useBufferIO... bool) string {
  7. useBufferedIO := false
  8.  
  9. ll := len(useBufferIO)
  10. if ll > 0 {
  11. useBufferedIO = useBufferIO[0]
  12. }
  13. cmd0 := Command(cmd)
  14. stdout0, err := cmd0.StdoutPipe()
  15. if err != nil {
  16. fmt.Printf("Error: Couldn't obtain the stdout pipe for command : %s\n", err)
  17. return ""
  18. }
  19. defer stdout0.Close()
  20. if err := cmd0.Start(); err != nil {
  21. fmt.Printf("Error: The command can not be startup: %s\n", err)
  22. return ""
  23. }
  24. if !useBufferedIO {
  25. var outputBuf0 bytes.Buffer
  26. for {
  27. tempOutput := make([]byte, 1024)
  28. n, err := stdout0.Read(tempOutput)
  29. if err != nil {
  30. if err == io.EOF {
  31. break
  32. } else {
  33. fmt.Printf("Error: Couldn't read data from the pipe: %s\n", err)
  34. return ""
  35. }
  36. }
  37. if n > 0 {
  38. outputBuf0.Write(tempOutput[:n])
  39. }
  40. }
  41. //fmt.Printf("%s\n", outputBuf0.String())
  42. res := fmt.Sprintf("%v",outputBuf0.String())
  43. return res
  44. } else {
  45. outputBuf0 := bufio.NewReader(stdout0)
  46. var resBuffer bytes.Buffer
  47.  
  48. for{
  49. //outputBuf0 默认带一个4K的缓冲区,第二个参数为false表示读取完所有的行
  50. output0, _, err := outputBuf0.ReadLine()
  51.  
  52. if err != nil {
  53. if err == io.EOF{
  54. break
  55. }
  56. fmt.Printf("Error: Couldn't read data from the pipe: %s\n", err)
  57. return ""
  58. }
  59. output0 = append(output0,'\n')
  60. resBuffer.Write(output0)
  61. }
  62. res := fmt.Sprintf("%v",resBuffer.String())
  63. return res
  64. }
  65. }
  66.  
  67. func Command(cmds []string) *exec.Cmd {
  68. name:= cmds[0]
  69. cmd := &exec.Cmd{
  70. Path: name,
  71. Args: cmds,
  72. }
  73.  
  74. if filepath.Base(name) == name {
  75. if lp, err := exec.LookPath(name); err != nil {
  76. //cmd.lookPathErr = err
  77. ErrorHandle(err)
  78. } else {
  79. cmd.Path = lp
  80. }
  81. }
  82. return cmd
  83. }
  1. func a11() {
  2. //命令行参数不能包含空格,比如-ht 是错的,-ht是对的
  3. cmd := []string{"/opt/wks/go/dbm_go/src/dbm/consistency/consis_0.6.7", "-cht", "192.168.177.67", "-cpt", "3316", "-ht","114.67.105.113,192.168.177.67", "-pt","3306,3316", "-slot", "-json", "-db", "vodb", "-timeStart", "2020-09-11 14:09:27", "-pl", "2"}
  4. res := tools.PipCmd(cmd,true)
  5. fmt.Println(res)
  6. }

管道的返回值

  1. stdout0, err := cmd0.StdoutPipe()
  1. // StdoutPipe returns a pipe that will be connected to the command's
  2. // standard output when the command starts.
  3. //
  4. // Wait will close the pipe after seeing the command exit, so most callers
  5. // need not close the pipe themselves. It is thus incorrect to call Wait
  6. // before all reads from the pipe have completed.
  7. // For the same reason, it is incorrect to call Run when using StdoutPipe.
  8. // See the example for idiomatic usage.
  9. func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
  10. if c.Stdout != nil {
  11. return nil, errors.New("exec: Stdout already set")
  12. }
  13. if c.Process != nil {
  14. return nil, errors.New("exec: StdoutPipe after process started")
  15. }
  16. pr, pw, err := os.Pipe()
  17. if err != nil {
  18. return nil, err
  19. }
  20. c.Stdout = pw
  21. c.closeAfterStart = append(c.closeAfterStart, pw)
  22. c.closeAfterWait = append(c.closeAfterWait, pr)
  23. return pr, nil
  24. }

管道返回一个

  1. io.ReadCloser
  1. // ReadCloser is the interface that groups the basic Read and Close methods.
  2. type ReadCloser interface {
  3. Reader
  4. Closer
  5. }

不仅实现了读接口,还可以进行关闭操作

管道的内部实现

  1. pr, pw, err := os.Pipe()

    系统创建了一个管道Pipe,内部加了读锁syscall.RorkLock.RLock(),然后返回一个读文件句柄pr,和一个写文件句柄pw

  1. // Pipe returns a connected pair of Files; reads from r return bytes written to w.
  2. // It returns the files and an error, if any.
  3. func Pipe() (r *File, w *File, err error) {
  4. var p [2]int
  5.  
  6. e := syscall.Pipe2(p[0:], syscall.O_CLOEXEC)
  7. // pipe2 was added in 2.6.27 and our minimum requirement is 2.6.23, so it
  8. // might not be implemented.
  9. if e == syscall.ENOSYS {
  10. // See ../syscall/exec.go for description of lock.
  11. syscall.ForkLock.RLock()
  12. e = syscall.Pipe(p[0:])
  13. if e != nil {
  14. syscall.ForkLock.RUnlock()
  15. return nil, nil, NewSyscallError("pipe", e)
  16. }
  17. syscall.CloseOnExec(p[0])
  18. syscall.CloseOnExec(p[1])
  19. syscall.ForkLock.RUnlock()
  20. } else if e != nil {
  21. return nil, nil, NewSyscallError("pipe2", e)
  22. }
  23.  
  24. return newFile(uintptr(p[0]), "|0", kindPipe), newFile(uintptr(p[1]), "|1", kindPipe), nil
  25. }

读方法

  1. // Reader is the interface that wraps the basic Read method.
  2. //
  3. // Read reads up to len(p) bytes into p. It returns the number of bytes
  4. // read (0 <= n <= len(p)) and any error encountered. Even if Read
  5. // returns n < len(p), it may use all of p as scratch space during the call.
  6. // If some data is available but not len(p) bytes, Read conventionally
  7. // returns what is available instead of waiting for more.
  8. //
  9. // When Read encounters an error or end-of-file condition after
  10. // successfully reading n > 0 bytes, it returns the number of
  11. // bytes read. It may return the (non-nil) error from the same call
  12. // or return the error (and n == 0) from a subsequent call.
  13. // An instance of this general case is that a Reader returning
  14. // a non-zero number of bytes at the end of the input stream may
  15. // return either err == EOF or err == nil. The next Read should
  16. // return 0, EOF.
  17. //
  18. // Callers should always process the n > 0 bytes returned before
  19. // considering the error err. Doing so correctly handles I/O errors
  20. // that happen after reading some bytes and also both of the
  21. // allowed EOF behaviors.
  22. //
  23. // Implementations of Read are discouraged from returning a
  24. // zero byte count with a nil error, except when len(p) == 0.
  25. // Callers should treat a return of 0 and nil as indicating that
  26. // nothing happened; in particular it does not indicate EOF.
  27. //
  28. // Implementations must not retain p.
  29. type Reader interface {
  30. Read(p []byte) (n int, err error)
  31. }

实现读接口的对象,有一个Read方法,可以将字节读到字节数组中; 与stdin设备对应,从该设备读取字节到内存。

  1. exec.Cmd这是一个外部命令,它可以是一个静止的命令,或者一个正在运行的命令;提供启动/停止/管道/输入输入定向支持;其中管道返回一个读文件句柄和一个写文件句柄

exec.Cmd输入输出重定向

  1. func runCmdWithPipe() {
  2. fmt.Println("Run command `ps -ef | grep apipe`: ")
  3. cmd1 := exec.Command("ps", "-ef")
  4. cmd2 := exec.Command("grep", "apipe")
  5. var outputBuf1 bytes.Buffer
  6. cmd1.Stdout = &outputBuf1
  7. if err := cmd1.Start(); err != nil {
  8. fmt.Printf("Error: The first command can not be startup %s\n", err)
  9. return
  10. }
  11. if err := cmd1.Wait(); err != nil {
  12. fmt.Printf("Error: Couldn't wait for the first command: %s\n", err)
  13. return
  14. }
  15. cmd2.Stdin = &outputBuf1
  16. var outputBuf2 bytes.Buffer
  17. cmd2.Stdout = &outputBuf2
  18. if err := cmd2.Start(); err != nil {
  19. fmt.Printf("Error: The second command can not be startup: %s\n", err)
  20. return
  21. }
  22. if err := cmd2.Wait(); err != nil {
  23. fmt.Printf("Error: Couldn't wait for the second command: %s\n", err)
  24. return
  25. }
  26. fmt.Printf("%s\n", outputBuf2.Bytes())
  27. }

go channel 概述 - 管道的更多相关文章

  1. Channel概述

    前言 前两篇文章介绍了NIO核心部分部分之一的缓冲区的相关内容,接下来我们继续学习NIO中另一个重要的核心部分--Channel(通道). 在学习这篇文章之前,先做下简单的说明,本文是一篇关于通道的概 ...

  2. go channel 概述

    精髓 将资源读进内存-->共享内存,一个个进程/线程进行处理,这是常见模式.go channel 是一种直接在进程/线程之间传递资源的方式,即以通信来共享内存.这便是go的精髓. 扩展-一些名词 ...

  3. [Go] 利用channel形成管道沟通循环内外

    这个要解决的问题是,比如如果有一个大循环,取自一个大的文件,要进行逻辑处理,那么这个逻辑的代码要放在循环每一行的循环体里面,这样有可能会出现一个for循环的逻辑嵌套,一层又一层,类似俄罗斯套娃.如果放 ...

  4. GO 总章

    GO 学习资源 go 代理 GO 语言结构 GO 数字运算 GO 时间处理 GO 定时器 GO 异常处理 go recover让崩溃的程序继续执行 GO Exit Fatal panic GO 通过进 ...

  5. GoLang的概述

    GoLang的概述 1.什么是程序 完成某个功能的指令的集合 2.Go语言的诞生小故事 2.1. 开发团队-三个大牛 2.2.Google创造Golang的原因 2.3.Golang 的发展历程 20 ...

  6. 第四章:管道与FIFO

    4.1:概述 管道是最初的Unix IPC形式,可追溯到1973年的Unix第三版.尽管对于许多操作来说很有用,但它们的根本局限在于没有名字,从而只能由亲缘关系的进程使用.这一点随FIFO的加入得改正 ...

  7. 第4章 管道与FIFO

    4.1 概述 管道只在亲缘进程间使用,FIFO在任意进程间使用 4.2 管道 #include <unistd.h> ]) fd[0]用来读管道,fd[1]用来写管道 1)命令who |  ...

  8. Go语言学习笔记(七)杀手锏 Goroutine + Channel

    加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 Goroutine Go语言的主要的功能在于令人简易使用的并行设计,这个方法叫做Goroutine,通过Gorou ...

  9. go语言之行--golang核武器goroutine调度原理、channel详解

    一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...

随机推荐

  1. Python常用的数据文件存储的4种格式(txt/json/csv/excel)及操作Excel相关的第三方库(xlrd/xlwt/pandas/openpyxl)(2021最新版)

    序言:保存数据的方式各种各样,最简单的方式是直接保存为文本文件,如TXT.JSON.CSV等,除此之外Excel也是现在比较流行的存储格式,通过这篇文章你也将掌握通过一些第三方库(xlrd/xlwt/ ...

  2. Redis INFO CPU 信息详解

    一.INFO CPU 通过INFO CPU命令可以查看Redis进程对于CPU的使用情况,如下: 这几个字段的含义如下所示: used_cpu_sys: System CPU consumed by ...

  3. 手把手从0到1:搭建Kubernetes集群

    搭建 k8s 集群网上很多教程,如果是手工部署或者实验环境可以直接使用 MiniKube 或者 Kind,来在本地启动简单的 Kubernetes 集群进行后面的学习即可.如果是使用 MiniKube ...

  4. 【数据结构&算法】09-队列概念&参考源码

    目录 前言 队列的定义 队列的抽象数据类型 循环队列与链式队列对比 循环队列 特点 定义 循环队列相关计算 链式队列 定义 阻塞队列 并发队列 代码实现 循环队列代码 链式队列实现 前言 李柱明博客: ...

  5. 大一C语言学习笔记(2)---快捷键篇

    大家好,博主呢,是一位刚刚步入大一的软件工程专业的大学生,之所以写博客,是想要与同样刚刚接触程序员一行的朋友们一起讨论,进步,在这里记录我的一些学习笔记及心得,希望通过这些点点滴滴的努力,可以让我们离 ...

  6. python实现高斯滤波

    一,定义 核是:3 *3     均值滤波 二,高斯函数 Y方向的方差与X方向的一致.处理后图像看起来更模糊(滤波明显)的话,核要更大. (三)代码实现 (四)核计算 (五)图像产生高斯噪声循环代码实 ...

  7. [luogu5163]WD与地图

    将删边改为插边,如果是无向图直接线段树合并即可,考虑如何将有向边转换为无向边 令$t_{i}$表示当插入到第$t_{i}$条边时恰好满足$x_{i}$与$y_{i}$在同一个强连通分量中,然后分类讨论 ...

  8. HDC技术分论坛:HarmonyOS新一代UI框架的全面解读

    作者:yuzhiqiang,UI编程框架首席技术专家 在Harmony 3.0.0开发者预览版中,包含了新一代的声明式UI框架ArkUI 3.0.多语言跨平台编译器ArkCompiler 3.0.跨端 ...

  9. stat命令的实现-mysate(必做)

    学习使用stat(1),并用C语言实现 1. 提交学习stat(1)的截图 使用 man 1 stat 查看帮助手册 从图中可以看到stat的用法是display file or file syste ...

  10. 【状压dp】Hamiton路径

    描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点 ...