Prompt user after reading from piped input in Golang

Viewed 67

I'm having some troubles reading from piped input, and then prompting a user for a further question afterwards. Is this possible to do?

I've created a simplified version of the program here.

I want the user to be able to pipe input in to the program instead of being prompted for it. However, I still want to prompt them with a second question if they don't provide a specific flag in a CLI program I'm writing.

To avoid any prompts, the user could pass in -y (not shown in the program below) along with piping in the text input to skip the "are you sure?" prompt.

package main

import (
    "fmt"
    "os"

    "github.com/AlecAivazis/survey/v2"
)

func main() {
    value := ""

    isPiped, err := isPipedInput()
    if err != nil {
        panic(err)
    }

    if isPiped {
        _, err = fmt.Scanf("%s", &value)
        if err != nil {
            panic(err)
        }
        if value == "" {
            panic(fmt.Errorf("must be greater than 0"))
        }

    } else {
        err = survey.AskOne(&survey.Input{Message: "Enter value followed by [Enter]:"}, &value)
        if err != nil {
            panic(err)
        }
        if value == "" {
            panic(fmt.Errorf("must be greater than 0"))
        }
    }

    shouldProceed := false
    err = survey.AskOne(&survey.Confirm{Message: "Are you sure?"}, &shouldProceed)
    if err != nil {
        panic(err)
    }
    if shouldProceed {
        fmt.Println("Proceeding!", value)
    } else {
        fmt.Println("Not proceeding...", value)
    }
}

func isPipedInput() (bool, error) {
    fi, err := os.Stdin.Stat()
    if err != nil {
        return false, err
    }

    return (fi.Mode() & os.ModeCharDevice) == 0, nil
}

To build:

go build -o main

First use-case that works as expected:

./main
? Enter value followed by [Enter]: foo
? Are you sure? Yes
Proceeding! foo

Second use case that does not work:

echo "foo" | ./main
? Are you sure? (y/N) ^[[23;256Rpanic: EOF

goroutine 1 [running]:
main.main()
        /main.go:40 +0x2b0
^[[8;23R%                                            
1 Answers

Looks like what you're trying to do isn't supported with Survey

https://github.com/AlecAivazis/survey#faq

survey aims to support most terminal emulators; it expects support for ANSI escape sequences. This means that reading from piped stdin or writing to piped stdout is not supported, and likely to break your application in these situations. See 337

From the looks of your code, it doesn't seem like you really need Survey if you're just prompting the user for input. Might be best to implement the prompt yourself.

Related