Search code examples
goinputoutputcommand-line-interfacegoroutine

How to take input when outputting?


What I'm trying to achieve is some kind of an application that logs a lot of information into the console (for instance, numbers from 0 to 1000000000000) and an ability to stop the execution by typing a command in the console (for example "stop").

I came up with an idea of using goroutines, however, I can't type in commands because the input field is changing to output.

Here is my code:

package main

import (
    "bufio"
    "os"
)

var process bool = true

func commandHandler() {
    reader := bufio.NewReader(os.Stdin)
    for process {
        text, _ := reader.ReadString('\n')
        if text == "stop\r\n" {
            process = false
        }
    }
}

func task() {
    var i int64 = 0
    for ; i < 10000000000 || process; i++ {
        if i%30000000 == 0 { // Just to slow down an output for a while
            println(i)
        }
    }
}

func main() {
    go task()
    commandHandler()
}

And the result that I get. Letters are my input that I`m trying to type in and numbers - the output of the application

Any suggestions on how to make proper input\output in my Go application?


Solution

  • I can't type in commands because the input field is changing to output

    You can type in the commands just fine. They'll be echoed to your console as you type them. This will be combined with everything else that is being output to your console, which can be confusing to the user - but not to the computer.

    Your program works just fine, assuming this actually matches on your OS:

            if text == "stop\r\n" {
    

    On my OS there's no \r. A more portable method would be to use strings.TrimSpace to remove all the whitespace.

    import (
      ...
      "strings"
    ) 
    ... 
    ...
            if strings.TrimSpace(text) == "stop" {
    

    With this change, the code works for me. As you said, the output and input is interpolated onto the screen, but you can still type stop and end the program.

    Any suggestions on how to make proper input\output in my Go application?

    Almost no real world terminal programs are interactive. Instead command line arguments and environment variables provide their configurationat invocation time. Shell redirection is typically used to retain (in a file) or paginate (eg |less) any long output of a program.

    You'll see a lot of academic programming using interactive terminal models where the program prompts the user and collects data, but in the real world this is very rare and is generally an ill advised complication. Standard input is typically used to provide data input for computation, rather than user commands (for example, data to be manipulated or filtered).

    As @tinkerer suggests, signals can already be used to terminate your program (details are OS specific). So there's really no need to worry about how a terminal application would handle the visual representation of standard input and output being interpolated just to terminate the program. In a Posix environment there are a number of other signals, some of which are entirely user oriented and can be used for arbitrary purposes.

    Once more complicated user input is required at runtime, the program typically listens on a socket for commands. For this kind of program, web interfaces serving HTTP have become increasingly common for the simplicity and accessibility.