How can I read from standard input in the console?
Categories:
Reading from Standard Input in Go: A Comprehensive Guide

Learn various methods to read user input from the console in Go, from basic line-by-line reading to more advanced buffered and formatted input techniques.
Interacting with users via the console is a fundamental aspect of many command-line applications. In Go, reading from standard input (stdin) can be achieved through several approaches, each suited for different scenarios. This article will guide you through the most common and effective ways to capture user input, whether it's a single line, a character, or formatted data.
Basic Line-by-Line Input with bufio.Scanner
For reading input line by line, especially when dealing with potentially large inputs or an unknown number of lines, the bufio.Scanner
is the most idiomatic and efficient choice in Go. It wraps an io.Reader
(like os.Stdin
) and provides a convenient way to iterate over lines or words.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Print("Enter your name: ")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan() // Read the next line
name := scanner.Text() // Get the scanned text
fmt.Printf("Hello, %s!\n", name)
// Example of reading multiple lines until an empty line is entered
fmt.Println("\nEnter multiple lines (press Enter on an empty line to finish):")
var lines []string
for scanner.Scan() {
line := scanner.Text()
if line == "" {
break // Exit loop on empty line
}
lines = append(lines, line)
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "Error reading input:", err)
}
fmt.Println("You entered:")
for i, l := range lines {
fmt.Printf("%d: %s\n", i+1, l)
}
}
Reading single and multiple lines using bufio.Scanner
.
scanner.Err()
after the scanning loop to catch any potential I/O errors that might have occurred during input reading.Reading Formatted Input with fmt.Scan
and fmt.Scanf
When you need to read specific data types (integers, floats, strings) directly and in a formatted manner, the fmt
package provides fmt.Scan
, fmt.Scanln
, and fmt.Scanf
. These functions are convenient for simple cases but can be less robust for complex or unpredictable input streams compared to bufio.Scanner
.
package main
import (
"fmt"
)
func main() {
var age int
fmt.Print("Enter your age: ")
_, err := fmt.Scan(&age) // Read an integer
if err != nil {
fmt.Println("Error reading age:", err)
return
}
fmt.Printf("You are %d years old.\n", age)
var firstName, lastName string
fmt.Print("Enter your first and last name (separated by space): ")
_, err = fmt.Scanln(&firstName, &lastName) // Read two strings, stopping at newline
if err != nil {
fmt.Println("Error reading names:", err)
return
}
fmt.Printf("Your full name is %s %s.\n", firstName, lastName)
var item string
var quantity int
var price float64
fmt.Print("Enter item, quantity, and price (e.g., 'Apple 5 1.20'): ")
_, err = fmt.Scanf("%s %d %f\n", &item, &quantity, &price) // Formatted input
if err != nil {
fmt.Println("Error reading item details:", err)
return
}
fmt.Printf("You bought %d %s(s) at $%.2f each.\n", quantity, item, price)
}
Using fmt.Scan
, fmt.Scanln
, and fmt.Scanf
for formatted input.
fmt.Scan
functions, be aware that they consume input up to the next whitespace or according to the format string. This can sometimes leave leftover characters in the input buffer, affecting subsequent reads. For more robust input handling, especially when mixing different input types, bufio.Scanner
or bufio.Reader
combined with manual parsing is often preferred.Low-Level Input with bufio.Reader
For more granular control over input, such as reading a single character, a specific number of bytes, or peeking into the buffer, bufio.Reader
is the tool of choice. It provides buffered I/O operations on top of os.Stdin
.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Press any key to continue...")
char, _, err := reader.ReadRune() // Read a single rune (character)
if err != nil {
fmt.Println("Error reading character:", err)
return
}
fmt.Printf("You pressed: %c\n", char)
// Clear the rest of the line after reading a single character
// This is important if you want to read another input later
_, _ = reader.ReadString('\n')
fmt.Print("Enter a sentence: ")
sentence, err := reader.ReadString('\n') // Read until newline
if err != nil {
fmt.Println("Error reading sentence:", err)
return
}
fmt.Printf("You entered: %s", sentence) // sentence already includes newline
}
Reading single characters and lines with bufio.Reader
.
flowchart TD A[Start Program] --> B{Need Input?} B -- Yes --> C{What kind of input?} C -- Line-by-line --> D[Use bufio.Scanner] C -- Formatted (int, string) --> E[Use fmt.Scan/Scanf] C -- Single char/Low-level --> F[Use bufio.Reader] D --> G[Process Input] E --> G F --> G G --> H{More Input?} H -- Yes --> B H -- No --> I[End Program]
Decision flow for choosing the right Go standard input method.
Choosing the right method depends on your specific needs. For most common scenarios, bufio.Scanner
is the recommended approach due to its simplicity and efficiency for line-based input. Use fmt.Scan
functions for quick, formatted input where error handling is less critical, and bufio.Reader
for fine-grained control over the input stream.