英文:
Running external python in Golang, Catching continuous exec.Command Stdout
问题
你可以使用管道(Pipe)来实现并发地捕获Python脚本的输出并打印到Go语言的终端上。以下是修改后的代码示例:
cmd := exec.Command("python", "game.py")
// 创建管道
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
// 启动Python脚本
err = cmd.Start()
if err != nil {
panic(err)
}
// 并发地读取并打印Python脚本的输出
go func() {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}()
// 等待Python脚本执行完毕
err = cmd.Wait()
if err != nil {
panic(err)
}
这样,你就可以同时运行Python脚本并实时捕获其输出,然后在Go语言的终端上打印出来。
英文:
So my go script will call an external python like this
cmd = exec.Command("python","game.py")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
go func(){
err := cmd.Run()
if err != nil{
panic(err)
}
}()
It runs my python script concurrently which is awesome.
But now the problem is, my python script will run infinitely and it will print out some information from time to time. I want to "catch" these Stdout and print them out on my golang terminal. How do I do it concurrently (without waiting my python script to exit)?
答案1
得分: 7
使用cmd.Start()
和cmd.Wait()
代替cmd.Run()
。
https://golang.org/pkg/os/exec/#Cmd.Run
Run启动指定的命令并等待其完成。
Start启动指定的命令,但不等待其完成。
Wait等待命令退出。它必须由Start启动。
如果你想同时捕获stdout/stderr,可以使用cmd.StdoutPipe()
/ cmd.StderrPipe()
,并通过bufio.NewScanner()
读取。
package main
import (
"bufio"
"fmt"
"io"
"os/exec"
)
func main() {
cmd := exec.Command("python", "game.py")
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
panic(err)
}
err = cmd.Start()
if err != nil {
panic(err)
}
go copyOutput(stdout)
go copyOutput(stderr)
cmd.Wait()
}
func copyOutput(r io.Reader) {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
以下是一个用于重现实时输出的示例Python代码。stdout在Python中可能会被缓冲。可能需要显式刷新。
import time
import sys
while True:
print("Hello")
sys.stdout.flush()
time.sleep(1)
英文:
Use cmd.Start()
and cmd.Wait()
instead of cmd.Run()
.
https://golang.org/pkg/os/exec/#Cmd.Run
> Run starts the specified command and waits for it to complete.
>
> Start starts the specified command but does not wait for it to complete.
>
> Wait waits for the command to exit. It must have been started by Start.
And if you want to capture stdout/stderr concurrently, use cmd.StdoutPipe()
/ cmd.StderrPipe()
and read it by bufio.NewScanner()
package main
import (
"bufio"
"fmt"
"io"
"os/exec"
)
func main() {
cmd := exec.Command("python", "game.py")
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
panic(err)
}
err = cmd.Start()
if err != nil {
panic(err)
}
go copyOutput(stdout)
go copyOutput(stderr)
cmd.Wait()
}
func copyOutput(r io.Reader) {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
The following is a sample python code for reproducing real-time output. The stdout may be buffered in Python. Explicit flush may be required.
import time
import sys
while True:
print "Hello"
sys.stdout.flush()
time.sleep(1)
答案2
得分: 1
如果你想同时捕获标准输出和标准错误输出,确实需要使用cmd.StdoutPipe()
、cmd.StderrPipe()
、cmd.Start()
和cmd.Wait()
。
但正如文档中提到的(https://pkg.go.dev/os/exec#Cmd.StdoutPipe):
> 因此,在所有从管道中读取完成之前调用Wait是不正确的。
在调用cmd.Wait()
之前,你需要等待你的goroutine完成(参见以下线程:https://github.com/golang/go/issues/38268)。
英文:
If you want to capture stdout and stderr concurrently, indeed you need to use cmd.StdoutPipe()
, cmd.StderrPipe()
, cmd.Start()
and cmd.Wait()
.
But as mentioned in the documentation (https://pkg.go.dev/os/exec#Cmd.StdoutPipe):
> It is thus incorrect to call Wait before all reads from the pipe have completed.
You'll need to wait for you goroutines to finish before calling cmd.Wait()
(see the following thread: https://github.com/golang/go/issues/38268)
答案3
得分: 0
你可以使用添加标志"-u"来关闭缓冲:
cmd := exec.Command("python", "-u", "game.py")
https://docs.python.org/3/using/cmdline.html#cmdoption-u
https://bugs.python.org/issue526382
英文:
You can use add the flag -u
to turn off buffering,
cmd := exec.Command("python", "-u", "game.py")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论