Golang read multiple lines from stdin [SOLVED]


GOLANG Solutions, GO

Author: Tuan Nguyen
Reviewer: Deepak Prasad

Different methods to read multiple lines from STDIN

In this article, I will demonstrate multiline input in a Go terminal application. In the previous article, we discussed about how to parse multiple inputs from users in Golang. Now, we are going to  introduce 3 methods to read multiple lines from the console:

  • fmt.Scan()
  • bufio.Reader()
  • bufio.Scanner()

 

Method-1: Use fmt.Scan() to read multiple lines of text

func Scan(a ...any) (n int, err error): Scan scans text read from standard input, storing successive space-separated values into successive arguments. Newlines count as space. It returns the number of items successfully scanned.

In the example below, we use the Scan() function to read 3 lines from stdin and save each line as a variable.

package main

import (
	"fmt"
	"log"
)

func main() {
	fmt.Println("input text:")
	var line1, line2, line3 string
	_, err := fmt.Scan(&line1, &line2, &line3)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("3 lines of text: %s %s %s\n", line1, line2, line3)
}

Output:

input text:
line1
line2
line3
3 lines of text: line1 line2 line3

Note that the Scan() function considers newlines as spaces, so each line cannot contain space characters.

 

Method-2: Use bufio.Reader to read multiple lines of text

func (b *Reader) ReadString(delim byte) (string, error): ReadString reads until the first occurrence of delim in the input, returning a string containing the data up to and including the delimiter. If ReadString encounters an error before finding a delimiter, it returns the data read before the error and the error itself (often io.EOF).

We will show you an example of using ReadString() to input multiple lines of text until the line only contains space characters.

package main

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

func main() {
	fmt.Println("input text:")
	reader := bufio.NewReader(os.Stdin)

	var lines []string
	for {
		// read line from stdin using newline as separator
		line, err := reader.ReadString('\n')
		if err != nil {
			log.Fatal(err)
		}

		// if line is empty, break the loop
		if len(strings.TrimSpace(line)) == 0 {
			break
		}

		//append the line to a slice
		lines = append(lines, line)
	}

	//print out all the lines
	println(len(lines))
	fmt.Println("output:")
	for _, eachLine := range lines {
		fmt.Println(eachLine)
	}
}

Output:

input text:
This is GoLinuxCloud
Welcome to our website

output:
This is GoLinuxCloud

Welcome to our website

Note that the ReadString() function returns a string containing the data up to and including the delimiter, so all the lines will contain '\n' at the end of line.

 

Method-3: Use bufio.Scanner to read multiple lines of text until the empty line

func (s *Scanner) Text() string: Text returns the most recent token generated by a call to Scan as a newly allocated string holding its bytes.

Here is an example of using Scanner() to input multiple lines of text until the input line is empty.

package main

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

func main() {
	fmt.Println("input text:")
	scanner := bufio.NewScanner(os.Stdin)

	var lines []string
	for {
		scanner.Scan()
		line := scanner.Text()

		// break the loop if line is empty
		if len(line) == 0 {
			break
		}
		lines = append(lines, line)
	}

	err := scanner.Err()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("output:")
	for _, eachLine := range lines {
		fmt.Println(eachLine)
	}
}

Output:

input text:
Today is Sunday
Have a nice weekend!

output:
Today is Sunday
Have a nice weekend!

 

Read multiple lines of text from STDIN conditionally

We can modify the code from Section 3 to read lines from the console and add a condition to read until it reaches a line that only contains the 'Q' character.

package main

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

func main() {
	fmt.Println("input text:")
	scanner := bufio.NewScanner(os.Stdin)

	var lines []string
	for {
		scanner.Scan()
		line := scanner.Text()

		// break the loop if line is contains 'q' only
		if strings.ToLower(strings.TrimSpace(line)) == "q" {
			break
		}
		lines = append(lines, line)
	}

	err := scanner.Err()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("output:")
	for _, eachLine := range lines {
		fmt.Println(eachLine)
	}
}

Output:

input text:
Hello
This is our website

Q
output:
Hello
This is our website

 

Summary

There are some ways to input multiple lines from console in Golang

  • Using the fmt.Scan() in case reading multiple words where each word is on a separate line.
  • Using the bufio.Readerin case reading multiple lines together with the newline character at the end of each line.
  • Using bufio.Scanner, which allows us to get a list of input lines without the newline character at the end of each line, is the most recommended and universal method of reading multiple lines.

 

References

https://pkg.go.dev/bufio#Scanner.Scan
https://pkg.go.dev/fmt#Scan

 

Tuan Nguyen

Tuan Nguyen

He is proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

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 send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment