Streaming commands output progress问题解决了长时间运行命令的打印进度问题。
我尝试将打印代码放在goroutine中,但扫描程序声称已经立即点击EOF
并且for块永远不会被执行。
第一次执行bufio.scan
方法时执行的Scan()
代码是:
// We cannot generate a token with what we are holding.
// If we've already hit EOF or an I/O error, we are done.
if s.err != nil {
// Shut it down.
s.start = 0
s.end = 0
return false
}
如果我打印s.err
,则输出为EOF
。
我正在尝试运行的代码是:
cmd := exec.Command("some", "command")
c := make(chan int, 1)
go func(cmd *exec.Cmd, c chan int) {
stdout, _ := cmd.StdoutPipe()
<-c
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
m := scanner.Text()
fmt.Println(m)
}
}(cmd, c)
cmd.Start()
c <- 1
cmd.Wait()
想法是启动Goroutine,抓住cmd.stdout
,等待cmd
启动,然后开始处理它的输出。
结果是执行了长命令并且程序等待它完成,但没有任何内容打印到终端。
首次scanner.Scan()
stdout
已经达到EOF
时,是否知道为什么@Override
protected void onSaveInstanceState(Bundle outState) {
}
被调用了?
答案 0 :(得分:1)
cmd.Start()
之后开始c <- struct{}{}
并使用无缓冲的频道c := make(chan struct{})
1:等待使用频道,然后使用EOF
在defer func() { c <- struct{}{} }()
之后关闭管道,就像这个工作示例代码一样:
package main
import (
"bufio"
"fmt"
"os/exec"
)
func main() {
cmd := exec.Command("Streamer")
c := make(chan struct{})
go run(cmd, c)
c <- struct{}{}
cmd.Start()
<-c
if err := cmd.Wait(); err != nil {
fmt.Println(err)
}
fmt.Println("done.")
}
func run(cmd *exec.Cmd, c chan struct{}) {
defer func() { c <- struct{}{} }()
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
<-c
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
m := scanner.Text()
fmt.Println(m)
}
fmt.Println("EOF")
}
2:您也可以等待使用sync.WaitGroup
,就像这个工作示例代码一样:
package main
import (
"bufio"
"fmt"
"os/exec"
"sync"
)
var wg sync.WaitGroup
func main() {
cmd := exec.Command("Streamer")
c := make(chan struct{})
wg.Add(1)
go func(cmd *exec.Cmd, c chan struct{}) {
defer wg.Done()
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
<-c
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
m := scanner.Text()
fmt.Println(m)
}
}(cmd, c)
c <- struct{}{}
cmd.Start()
wg.Wait()
fmt.Println("done.")
}
和Streamer示例代码(仅用于测试):
package main
import "fmt"
import "time"
func main() {
for i := 0; i < 10; i++ {
time.Sleep(1 * time.Second)
fmt.Println(i, ":", time.Now().UTC())
}
}
并查看func (c *Cmd) StdoutPipe() (io.ReadCloser, error)
文档:
StdoutPipe返回一个将连接到命令的管道 命令启动时的标准输出。
等待将在看到命令退出后关闭管道,所以大多数 来电者不需要自己关闭管道;然而,一个含义是 在从管道读取所有内容之前调用Wait是不正确的 完成。出于同样的原因,使用时调用Run是不正确的 StdoutPipe。请参阅惯用法示例。
答案 1 :(得分:0)
来自godocs:
StdoutPipe返回一个将连接到命令的管道 命令启动时的标准输出。
等待将在看到命令退出后关闭管道,所以大多数 来电者不需要自己关闭管道;然而,一个含义是 在从管道读取所有内容之前调用Wait是不正确的 完成。
您在启动命令后立即调用Wait()
。因此,一旦命令完成,管道就会关闭,然后确保已从管道中读取所有数据。在扫描循环后尝试将Wait()
移动到您的例行程序。
go func(cmd *exec.Cmd, c chan int) {
stdout, _ := cmd.StdoutPipe()
<-c
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
m := scanner.Text()
fmt.Println(m)
}
cmd.Wait()
c <- 1
}(cmd, c)
cmd.Start()
c <- 1
// This is here so we don't exit the program early,
<-c
还有一种更简单的方法,就是将os.stdout指定为cmd的标准输出,导致命令直接写入os.stdout:
cmd := exec.Command("some", "command")
cmd.Stdout = os.Stdout
cmd.Run()