doulilou8560 2018-08-06 06:57
浏览 187
已采纳

将文件用作Stdin(Golang)时,在第二提示符下获得EOF

I am trying to do functional testing of a cli app similar to this way.

As the command asks a few input on command prompt, I am putting them in a file and setting it as os.Stdin.

cmd := exec.Command(path.Join(dir, binaryName), "myArg")
tmpfile := setStdin("TheMasterPassword
SecondAnswer
12121212
")
cmd.Stdin = tmpfile
output, err := cmd.CombinedOutput()

The setStdin just creates a tmpFile, write the string in file and returns the *os.File.

Now, I am expecting TheMasterPassword to be first input, and it's working. But for the second input always getting Critical Error: EOF.

The function I am using for asking and getting user input this :

func Ask(question string, minLen int) string {
    reader := bufio.NewReader(os.Stdin)

    for {
        fmt.Printf("%s: ", question)

        response, err := reader.ReadString('
')
        ExitIfError(err)

        if len(response) >= minLen {
            return strings.TrimSpace(response)
        } else {
            fmt.Printf("Provide at least %d character.
", minLen)
        }
    }
}

Can you please help me to find out what's going wrong? Thanks a lot!

Adding setStdin as requested

func setStdin(userInput string) *os.File {
    tmpfile, err := ioutil.TempFile("", "test_stdin_")
    util.ExitIfError(err)

    _, err = tmpfile.Write([]byte(userInput))
    util.ExitIfError(err)
    _, err = tmpfile.Seek(0, 0)
    util.ExitIfError(err)

    return tmpfile
}
  • 写回答

1条回答 默认 最新

  • douyigua5381 2018-08-06 07:28
    关注

    It pretty much looks like in your app your call Ask() whenever you want a single input line.

    Inside Ask() you create a bufio.Reader to read from os.Stdin. Know that bufio.Reader–as its name suggests–uses buffered reading, meaning it may read more data from its source than what is returned by its methods (Reader.ReadString() in this case). Which means if you just use it to read one (or some) lines and you throw away the reader, you will throw away buffered, unread data.

    So next time you call Ask() again, attempting to read from os.Stdin, you will not continue from where you left off...

    To fix this issue, only create a single bufio.Reader from os.Stdin, store it in a global variable for example, and inside Ask(), always use this single reader. So buffered and unread data will not be lost between Ask() calls. Of course this solution will not be valid to call from multiple goroutines, but reading from a single os.Stdin isn't either.

    For example:

    var reader = bufio.NewReader(os.Stdin)
    
    func Ask(question string, minLen int) string {
        // use the global reader here...
    }
    

    Also note that using bufio.Scanner would be easier in your case. But again, bufio.Scanner may also read more data from its source than needed, so you have to use a shared bufio.Scanner here too. Also note that Reader.ReadString() returns you a string containing the delimeter (a line ending with in your case) which you probably have to trim, while Scanner.Text() (with the default line splitting function) will strip that first before returning the line. That's also a simplification you can take advantage of.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上
  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解