猿问

执行外部程序/脚本并检测是否请求用户输入

给出以下示例:


// test.go

package main


import (

        "fmt"

        "os/exec"

)


func main() {

    cmd := exec.Command("login")

    in, _ := cmd.StdinPipe()

    in.Write([]byte("user"))

    out, err := cmd.CombinedOutput()

    if err != nil {

         fmt.Println("error:", err)

        }

    fmt.Printf("%s", out)

}

我如何检测到该过程正在等待用户输入而无法完成?


我试图能够运行任何脚本,但是如果由于某种原因它试图从stdin读取而中止它。


谢谢!


陪伴而非守候
浏览 225回答 3
3回答

开满天机

检测该过程将不会完成是一个困难的问题。实际上,它是计算机科学中最经典的“无法解决”的问题之一:暂停问题。通常,当您调用exec.Command并且不传递任何输入时,它将导致程序从操作系统的null设备读取(请参阅exec.Cmd字段中的文档)。在您的代码(以及下面的代码)中,您显式创建了一个管道(尽管您应检查错误返回,StdinPipe以防未正确创建),因此应随后调用in.Close()。无论哪种情况,子进程都将获得EOF,并且应在其自身之后清除并退出。为了帮助无法正确处理输入或以其他方式卡住自己的进程,通常的解决方案是使用超时。在Go中,您可以为此使用goroutines:// Set your timeoutconst CommandTimeout = 5 * time.Secondfunc 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,可以在准备好读取输出时将其写入程序。

茅侃侃

尽管这不允许您“检测”试图从stdin读取的程序,但我只是关闭了stdin。这样,子进程在尝试读取时将仅收到EOF。大多数程序都知道如何处理封闭的stdin。// All error handling excludedcmd := exec.Command("login")in, _ := cmd.StdinPipe()cmd.Start()in.Close()cmd.Wait()不幸的是,这意味着您不能使用组合输出,以下代码应允许您执行相同的操作。它要求您导入bytes软件包。var buf = new(bytes.Buffer)cmd.Stdout = bufcmd.Stderr = buf之后cmd.Wait(),您可以执行以下操作:out := buf.Bytes()
随时随地看视频慕课网APP

相关分类

Go
我要回答