Reading Input

Command-line programs often need to read what the user types, or data piped in from another program. Go offers two main tools: fmt.Scan for quickly reading whitespace-separated values, and bufio.Scanner for reading line by line — the one you'll use most. This lesson covers both, plus converting and validating what you read.

Standard input

A running program has three standard streams: standard input (os.Stdin, normally the keyboard), standard output (os.Stdout, the terminal) and standard error (os.Stderr, also the terminal, for messages). Standard input can also come from a file or another program:

$
go run . < names.txt          # read from a file
echo "Ana" | go run .         # read another program's output

In this lesson each example shows the input it was given in an Input box. When you type input yourself, it appears on screen as you type; in the outputs here it doesn't, because it came from a file.

Reading lines with bufio.Scanner

A bufio.Scanner splits its input into lines. Each call to Scan reads the next line and returns false at the end of the input; Text returns the line without its newline:

GO
package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	fmt.Print("What's your name? ")
	scanner.Scan()
	name := scanner.Text()

	fmt.Print("Favourite colour? ")
	scanner.Scan()
	colour := scanner.Text()

	fmt.Printf("Hello, %s! %s is a great colour.\n", name, colour)
}
Input
Ana Lima
dark green
Output
What's your name? Favourite colour? Hello, Ana Lima! dark green is a great colour.

Reading whole lines means names and phrases with spaces come through intact.

Reading until the input ends

Put Scan in a loop to process every line. After the loop, scanner.Err() reports any read error (reaching the end of the input is not an error):

GO
package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	lines, words := 0, 0
	for scanner.Scan() {
		line := scanner.Text()
		lines++
		words += len(strings.Fields(line))
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "read error:", err)
		os.Exit(1)
	}
	fmt.Printf("%d lines, %d words\n", lines, words)
}
Input
The quick brown fox
jumps over
the lazy dog
Output
3 lines, 9 words

When typing at the keyboard, end the input with Ctrl+D (macOS, Linux) or Ctrl+Z then Enter (Windows). strings.Fields splits a line on any run of spaces or tabs.

To read word by word instead of line by line, call scanner.Split(bufio.ScanWords) before the loop. Lines longer than 64 KB make the scanner stop with an error; for huge lines, give it a bigger buffer with scanner.Buffer.

Reading numbers

Input arrives as text. Convert it with strconv and check the error, because users type all sorts of things:

GO
package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	total, count := 0.0, 0
	for scanner.Scan() {
		text := strings.TrimSpace(scanner.Text())
		if text == "" {
			continue
		}
		price, err := strconv.ParseFloat(text, 64)
		if err != nil {
			fmt.Printf("skipping %q: not a number\n", text)
			continue
		}
		total += price
		count++
	}
	fmt.Printf("%d prices, total %.2f\n", count, total)
}
Input
4.50
12.99

three
3.25
Output
skipping "three": not a number
3 prices, total 20.74

Quick input with fmt.Scan

fmt.Scan reads space-separated values straight into variables, converting them to each variable's type. You pass pointers to the variables (&x, lesson 37) so Scan can fill them in. It returns how many values it read and an error:

GO
package main

import "fmt"

func main() {
	var name string
	var age int
	fmt.Print("Name and age: ")
	n, err := fmt.Scan(&name, &age)
	if err != nil {
		fmt.Println("\nbad input:", err, "- read", n, "value(s)")
		return
	}
	fmt.Printf("\n%s will be %d next year\n", name, age+1)
}
Input
Ana thirty
Output
Name and age:
bad input: expected integer - read 1 value(s)

fmt.Scan is handy for exercises, but it treats newlines like spaces, stops at the first error and leaves the rest of the input unread, which makes recovering from bad input awkward. For real programs, read lines with a Scanner and parse them yourself, as above.

Try it yourself

Read a list of test scores, one per line, and print the highest, lowest and average.

Try it yourself · main.go
Edit the code, copy it into main.go in a new folder and run it with go run main.go (Go 1.27 or later). How to install Go
Input
72
95
61
88
Output
min 61, max 95, average 79.0
Next: making decisions with if.