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 fmt
, bufio
, and os
packages.
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:
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