Go Prompt - Create Interactive CLI prompts with Examples

In this post we'll demonstrate how to add various interactive go prompts to your Go-based CLI apps. We often use CLI tools and programs like bash, awk, sed, and many others for both work and play. Visit our shell scripting session to explore more.

 

Example 1: Go Prompt for single input

Standard input, often abbreviated stdin, is a stream from which a program reads its input data. To read input from users in Go, we use the fmtbufio, and os packages.

Advertisement

The basic text input prompt is easy to implement. Just read from standard input until the new line character (\n). In this below example, user can enter their name and our program will say "Hello + <their_name>, welcome to GoLinuxCloud website". We also use the strings.TrimSpace() function to remove white space before and after the string:

func TrimSpace(s string) string: TrimSpace returns a slice of the string s, with all leading and trailing white space removed, as defined by Unicode.

Example

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func NamePrompt(label string) string {
    var str string
    r := bufio.NewReader(os.Stdin)
    for {
        fmt.Fprint(os.Stderr, label+" ")
        str, _ = r.ReadString('\n')
        if str != "" {
            break
        }
    }
    return strings.TrimSpace(str)
}

func main() {
    name := NamePrompt("Enter your name:")
    fmt.Printf("Hello %s, welcome to GoLinuxCloud!\n", name)
}

Output:

Enter your name: Kristine
Hello Kristine, welcome to GoLinuxCloud!

 

Example 2: Interactive multiple inputs prompt

In this example, we will require user to answer some questions about their name, nationality, favorite color,... and a yes/no question.

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func InputPrompt(label string) string {
	var str string
	r := bufio.NewReader(os.Stdin)
	for {
		fmt.Fprint(os.Stderr, label+" ")
		str, _ = r.ReadString('\n')
		if str != "" {
			break
		}
	}
	return strings.TrimSpace(str)
}

func YesNoPrompt(label string) bool {
	choices := "Y/N (yes/no)"

	r := bufio.NewReader(os.Stdin)
	var s string

	for {
		fmt.Fprintf(os.Stderr, "%s (%s) ", label, choices)
		s, _ = r.ReadString('\n')
		s = strings.TrimSpace(s)
		s = strings.ToLower(s)
		if s == "y" || s == "yes" {
			return true
		} else if s == "n" || s == "no" {
			return false
		} else {
			return false
		}
	}
}

func main() {
	name := InputPrompt("Enter your name:")
	nationality := InputPrompt("Enter your nationality:")
	favouriteColor := InputPrompt("Enter your favourite color:")
	favouritePet := InputPrompt("Enter your favourite pet:")
	fmt.Printf("Hello %s from %s. Your favourite color is %s and favourite pet is %s. Welcome to GoLinuxCloud!\n", name, nationality, favouriteColor, favouritePet)

	yesNo := YesNoPrompt("Is this tutorial helpful?:")
	if yesNo {
		fmt.Println("Thank you!")
	} else {
		fmt.Println("Are you sure?")
	}
}

Output:

Advertisement
Enter your name: Bob
Enter your nationality: USA
Enter your favourite color: red
Enter your favourite pet: cat
Hello Bob from USA. Your favourite color is red and favourite pet is cat. Welcome to GoLinuxCloud!
Is this tutorial helpful?: (Y/N (yes/no)) y
Thank you!

 

Example 3: Create interactive CLI prompt in a loop

In the example below, we play Guess the Number game. You have to guess number from 1 to 100. If your guess is too high or too low, you'll get a hint. For read the int input, we will use Scanln() function in this example

func Scanln(a ...any) (n int, err error): Scanln is similar to Scan, but stops scanning at a newline and after the final item there must be a newline or EOF.

package main

import ("fmt"
"math/rand"

"time")


func main() {
	rand.Seed(time.Now().UnixNano())
	secretNum := rand.Intn(1, 100)
	var i int
	fmt.Println("Guess a number between 1 and 100")
	for true {
		fmt.Scanln(&i)
		if (i == secretNum) {
			fmt.Println("Congratulations, the secret number is:", i)
			break
		} else if (i> secretNum) {
			fmt.Println("You'r wrong, guess a smaller number")
		} else {
			fmt.Println("You'r wrong, guess a bigger number")
		}
	}
}

Output:

Guess a number between 1 and 100
6
Guess a bigger number
67
Guess a smaller number
45
Guess a smaller number
30
Guess a smaller number
25
Guess a smaller number
20
Guess a smaller number
15
Guess a smaller number
14
Guess a smaller number
13
Guess a smaller number
11
Congratulations, the secret number is: 11

 

Example 4: Perform input validation with each prompt

In the example 3, we do not check the input type. When user enter a string, the Scanln() function automatically convert it to 0. To avoid this you could just read to string and then use int, err := strconv.Atoi(string) like in code below. Note hereby that fmt.Scan or fmt.Scanln split input until the next space.

package main

import (
	"fmt"
	"strconv"
)

func main() {
    var s string
    var i int
    fmt.Println("Enter a number:")
    for {
        _, err := fmt.Scan(&s)
        i, err = strconv.Atoi(s)
        if err != nil {
            fmt.Println("Enter a valid number")
        } else {
            fmt.Println("Your input number is: " + strconv.Itoa(i))
            break
        }
    }
}

Output:

Enter a number:
sdasd
Enter a valid number
12.3
Enter a valid number
54
Your input number is: 54

You can read further about GO Cast - Perform type casting

 

Summary

In this article, I will show you how to use Interactive CLI prompts in Go. Using the methods described above, we can create a fun game or menu. If you want to multi-select prompt, you can read more about awesome survey package. As you can see, basic interactive prompts are fairly simple to implement, but for more complex ones, some Go packages from the community are recommended: Go prompt

 

References

https://pkg.go.dev/fmt

 

Categories GO

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment

X