我正试图从一个长期运行的(阻塞/类似shell的)命令中读取stdout,最终目的是创建一个Go可以与之交互的sidecar进程。
我有以下MCVE:
func main() {
var err error
// Build the long-running command
args := []string{"-i0", "-o0", "-e0", "/usr/local/bin/ipython"}
cmd := exec.Command("stdbuf", args...)
// Keep the stdin file descriptor open
// Spawned command should block waiting for input
_, err = cmd.StdinPipe()
if err != nil {
panic(err)
}
// Setup pipe of `Reader` type
var stdoutBuf []byte
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
// Start the command
if err = cmd.Start(); err != nil {
panic(err)
}
go func() {
for {
// Asynchronously continue reading from stdout
n, err := stdout.Read(stdoutBuf)
fmt.Println(n)
if err != nil {
panic(err)
}
fmt.Println(stdoutBuf)
time.Sleep(time.Millisecond * 2000)
}
}()
// Block forever
if err = cmd.Wait(); err != nil {
panic(err)
}
}
从理论上讲,这种方法似乎可行。我希望stdout.Read
会返回一些内容(ipython
shell序言),但是n
始终为0。
Reader.Read
为什么从不读取任何内容?StdoutPipe
?我认为该进程本身没有任何问题(这将导致读取无效的文件描述符),因为Start
不会panic
,并且似乎cmd.Wait
会永远阻塞
答案 0 :(得分:1)
在这个示例中,
Reader.Read
为什么从不读取任何内容?
因为您正在读取大小var stdoutBuf []byte
创建的大小为0的缓冲区。而是使用类似以下内容的
stdoutBuf := make([]byte, 4096)
您可能还想使用bufio
。
一些相关的问题:如果没有什么可阅读的,我有什么办法可以阻止阅读
StdoutPipe
?
stdout.Read
已经被阻止,这是io.Reader
的典型特征(尽管不是必需的):
如果一些数据可用,但不是len(p)个字节,按常规方式,Read将返回可用数据,而不是等待更多数据。 [...]除了len(p)== 0时,不建议返回零字节计数且没有错误。