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.

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

报告相同问题?

悬赏问题

  • ¥15 数学的三元一次方程求解
  • ¥20 iqoo11 如何下载安装工程模式
  • ¥15 本题的答案是不是有问题
  • ¥15 关于#r语言#的问题:(svydesign)为什么在一个大的数据集中抽取了一个小数据集
  • ¥15 C++使用Gunplot
  • ¥15 这个电路是如何实现路灯控制器的,原理是什么,怎么求解灯亮起后熄灭的时间如图?
  • ¥15 matlab数字图像处理频率域滤波
  • ¥15 在abaqus做了二维正交切削模型,给刀具添加了超声振动条件后输出切削力为什么比普通切削增大这么多
  • ¥15 ELGamal和paillier计算效率谁快?
  • ¥15 蓝桥杯单片机第十三届第一场,整点继电器吸合,5s后断开出现了问题