golang os/exec: get data from stdout in parts

huangapple go评论77阅读模式
英文:

golang os/exec: get data from stdout in parts

问题

我想在我的Go代码中使用os/exec来运行一个外部应用程序。这个应用程序是my_external_script.sh,它将数据输出到stdout,分为两部分:第一部分非常快(在三秒后向stdout写入"A"),而第二部分("B")只有在10秒后才会被写入。

例如:

./my_external_script.sh
.....
.....
A(经过3秒)
.....
.....
.....
.....
.....
.....
B(经过10秒)
(程序以0状态码退出)

我目前在我的Go代码中这样执行它:

func execMyExternalCmd() (*string, error) {
    cmd := exec.Command("my_external_script.sh")
    var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    if err != nil {
        return nil, err
    }
    var res = out.String()
    return &res, nil
}

问题是,execMyExternalCmd只有在10秒后才会返回,此时"A"和"B"都已经被写入并且程序已退出。我希望在stdout上的"A"可用时就开始使用它(但稍后也要使用"B")。我该如何实现这一点?

英文:

I want to run an external application from my go code using os/exec. The application my_external_script.sh outputs data to stdout in two parts: the first part is quite fast (it writes "A" to stdout after three seconds) and the second part ("B) is being written only after 10 seconds.

For example:

./my_external_script.sh
.....
.....
A (3 seconds elapsed)
.....
.....
.....
.....
.....
.....
B (10 seconds elapsed)
(program exits with 0 status code)

I'm currently executing this like so from my go code:

func execMyExternalCmd() (*string, error) {
	cmd := exec.Command("my_external_script.sh")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return nil, err
	}
	var res = out.String()
	return &res, nil
}

The problem is, execMyExternalCmd will only return after 10 seconds, where both "A" and "B" have been written and the program exited. I would like to use "A" as soon as it's available on the stdout (but also use "B" later on when it's available). How can I achieve this?

答案1

得分: 1

package main

import (
	"bufio"
	"log"
	"os/exec"
)

func main() {
	cmd := exec.Command("sh", "-c", "echo 1;sleep 10;echo 2;")

	outPipe, _ := cmd.StdoutPipe()
	scanner := bufio.NewScanner(outPipe)

	// 创建一个通道用于发送数据
	dataChan := make(chan string)

	go func() {
		for scanner.Scan() {
			// 将数据发送到通道
			dataChan <- scanner.Text()
		}
	}()

	cmd.Start()
	cmd.Wait()

	close(dataChan) // 关闭通道

	// 从通道中读取数据
	for data := range dataChan {
		log.Println(data)
	}

	log.Println("Done")
}

输出:

2016/12/04 17:11:09 1
2016/12/04 17:11:19 2
2016/12/04 17:11:19 Done

使用通道来从函数中发送数据,而不是使用返回值。

英文:
package main

import (
	&quot;bufio&quot;
	&quot;log&quot;
	&quot;os/exec&quot;
)

func main() {
	cmd := exec.Command(&quot;sh&quot;, &quot;-c&quot;, &quot;echo 1;sleep 10;echo 2;&quot;)

	outPipe, _ := cmd.StdoutPipe()
	scanner := bufio.NewScanner(outPipe)

	go func() {
		for scanner.Scan() {
			log.Println(scanner.Text())
		}
	}()

	cmd.Start()
	cmd.Wait()

	log.Println(&quot;Done&quot;)
}

Output:

2016/12/04 17:11:09 1
2016/12/04 17:11:19 2
2016/12/04 17:11:19 Done

Use channels to send data from the function instead of return.

huangapple
  • 本文由 发表于 2016年12月4日 21:00:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/40958903.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定