吾八哥博客

您现在的位置是:首页 > 码农手记 > Golang > 正文

Golang

Golang里实现实时读取shell命令输出

吾八哥2020-08-01Golang6157

使用golang调用阻塞式shell命令(如ping命令),按普通的调用方法是无法拿到实时输出结果的,这里可以通过异步读取管道输出数据的方式实现,关键代码如下:

package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os/exec"
	"runtime/debug"
	"sync"
)

func readLog(wg *sync.WaitGroup, out chan string, reader io.ReadCloser) {
	defer func() {
		if r := recover(); r != nil {
			log.Println(r, string(debug.Stack()))
		}
	}()
	defer wg.Done()
	r := bufio.NewReader(reader)
	for {
		line, _, err := r.ReadLine()
		if err == io.EOF || err != nil {
			return
		}
		out <- string(line)
	}
}

// RunCommand run shell
func RunCommand(out chan string, name string, arg ...string) error {
	cmd := exec.Command(name, arg...)
	stdout, _ := cmd.StdoutPipe()
	stderr, _ := cmd.StderrPipe()
	if err := cmd.Start(); err != nil {
		return err
	}
	wg := sync.WaitGroup{}
	defer wg.Wait()
	wg.Add(2)
	go readLog(&wg, out, stdout)
	go readLog(&wg, out, stderr)
	if err := cmd.Wait(); err != nil {
		return err
	}
	return nil
}

func main() {
	out := make(chan string)
	defer close(out)
	go func() {
		for {
			str, ok := <-out
			if !ok {
				break
			}
			fmt.Println(str)
		}
	}()
	args := []string{"-c", "ping www.5bug.wang"}
	if err := RunCommand(out, "bash", args...); err != nil {
		return
	}

}

执行效果如下:

1596214980760.jpg