如何在Golang中使用os / exec处理用户输入?我无法停止输入阶段

时间:2019-09-04 02:33:39

标签: go

首先,我从中构建一个名为exec.exe的命令:

package main
import "fmt"
func main() {
    var input string
    fmt.Println("input a value")
    fmt.Scanln(&input)
    fmt.Println(input)

    fmt.Println("input another value")
    fmt.Scanln(&input)
    fmt.Println(input)
}

然后我要使用os / exec pacage来运行它:

package main

import (
    "fmt"
    "os/exec"
)

func main() {
    cmd := exec.Command("G:\\go_workspace\\GOPATH\\src\\pjx\\modules\\exec\\exec")

    stdin, e := cmd.StdinPipe()
    if e != nil {
        panic(e)
    }
    stdout, e := cmd.StdoutPipe()
    if e != nil {
        panic(e)
    }
    if e:=cmd.Start();e!=nil {
        panic(e)
    }
    stdin.Write([]byte("hello"))
    var buf = make([]byte, 512)
    n, e := stdout.Read(buf)
    if e != nil {
        panic(e)
    }
    fmt.Println(string(buf[:n]))

    if e := cmd.Wait(); e != nil {
        panic(e)
    }
}

最后我运行它,结果将在用户输入阶段暂停,例如:

(如果未加载图片,则在输入阶段将其暂停)

please input a value:

1
12
232

unexpected result, pausing on user input stage

我是否以错误的方式使用了cmd管道?

3 个答案:

答案 0 :(得分:1)

您需要监听正在执行的程序的输出。当您编写“ hello”时,该程序可能仍在写入其标准输出。试试这个:

    go func() {
        in := bufio.NewReader(stdout)
        for {
            s, err := in.ReadString('\n')
            if err != nil {
                return
            }
            fmt.Println(s)
        }
    }()

    if e := cmd.Start(); e != nil {
        panic(e)
    }

    stdin.Write([]byte("hello\n"))
    stdin.Write([]byte("hello2\n"))
    if e := cmd.Wait(); e != nil {
        panic(e)
    }

答案 1 :(得分:1)

一种方法

cmd := exec.Command("...") // Change to your path
stdin, err := cmd.StdinPipe()
if err != nil {
    panic(err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
    panic(err)
}

buf := bytes.NewBuffer(nil)
// read the stdout continuously in a separate goroutine and capture it in buf
go func() {
    io.Copy(buf, stdout)
}()

if err := cmd.Start(); err != nil {
    panic(err)
}

stdin.Write([]byte("hello\n")) // Send \n to submit
stdin.Write([]byte("world\n"))

if err := cmd.Wait(); err != nil {
    panic(err)
}

fmt.Fprint(os.Stdout, buf)

结果:

➜ go run main.go
input a value
hello
input another value
world

答案 2 :(得分:1)

程序正在阻塞,因为子进程中的jar{ baseName = "libdemo" version = "1.0" manifest { attributes ('Main-Class': 'com.example.lib.Main') } from { configurations.extraLibs.collect { it.isDirectory() ? it : zipTree(it) } } } 正在等待fmt.Scanln字符(\n也将使其返回)。为避免阻塞,您的输入应包括两个EOF,或者您可以仅调用'stdin.Close()'来指示输入流已完成。

并且由于子流程多次调用\nScanln,因此对Println的单次调用可能无法读取子流程的完整输出。您可以继续调用stdout.Read,直到返回stdout.Read()错误为止,也可以只使用io.EOF

ioutil.ReadAll