3 回答
TA贡献1786条经验 获得超13个赞
检测该过程将不会完成是一个困难的问题。实际上,它是计算机科学中最经典的“无法解决”的问题之一:暂停问题。
通常,当您调用exec.Command并且不传递任何输入时,它将导致程序从操作系统的null设备读取(请参阅exec.Cmd字段中的文档)。在您的代码(以及下面的代码)中,您显式创建了一个管道(尽管您应检查错误返回,StdinPipe以防未正确创建),因此应随后调用in.Close()。无论哪种情况,子进程都将获得EOF,并且应在其自身之后清除并退出。
为了帮助无法正确处理输入或以其他方式卡住自己的进程,通常的解决方案是使用超时。在Go中,您可以为此使用goroutines:
// Set your timeout
const CommandTimeout = 5 * time.Second
func main() {
cmd := exec.Command("login")
// Set up the input
in, err := cmd.StdinPipe()
if err != nil {
log.Fatalf("failed to create pipe for STDIN: %s", err)
}
// Write the input and close
go func() {
defer in.Close()
fmt.Fprintln(in, "user")
}()
// Capture the output
var b bytes.Buffer
cmd.Stdout, cmd.Stderr = &b, &b
// Start the process
if err := cmd.Start(); err != nil {
log.Fatalf("failed to start command: %s", err)
}
// Kill the process if it doesn't exit in time
defer time.AfterFunc(CommandTimeout, func() {
log.Printf("command timed out")
cmd.Process.Kill()
}).Stop()
// Wait for the process to finish
if err := cmd.Wait(); err != nil {
log.Fatalf("command failed: %s", err)
}
// Print out the output
fmt.Printf("Output:\n%s", b.String())
}
在上面的代码中,实际上有3个主要的goroutine感兴趣:main goroutine产生子流程并等待其退出;如果未及时停止,则在后台发送计时器goroutine以终止该进程;还有一个goroutine,可以在准备好读取输出时将其写入程序。
TA贡献1842条经验 获得超21个赞
尽管这不允许您“检测”试图从stdin读取的程序,但我只是关闭了stdin。这样,子进程在尝试读取时将仅收到EOF。大多数程序都知道如何处理封闭的stdin。
// All error handling excluded
cmd := exec.Command("login")
in, _ := cmd.StdinPipe()
cmd.Start()
in.Close()
cmd.Wait()
不幸的是,这意味着您不能使用组合输出,以下代码应允许您执行相同的操作。它要求您导入bytes软件包。
var buf = new(bytes.Buffer)
cmd.Stdout = buf
cmd.Stderr = buf
之后cmd.Wait(),您可以执行以下操作:
out := buf.Bytes()
- 3 回答
- 0 关注
- 224 浏览
添加回答
举报