Golang multiline string and reading multiple lines from stdin

Golang multiline string with raw backticks and escapes; golang read stdin and golang read line from stdin using fmt.Scan tokens, bufio.Reader ReadString, and bufio.Scanner; EOF and token size notes; not golang multiline comment syntax.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Golang multiline string and reading multiple lines from stdin

Searchers landing on golang read multiple lines often want one of two things: a golang multiline string (or go multiline string) in source code, or golang read stdin / golang read line from stdin at runtime. This page covers both: raw and escaped multiline string golang forms, then read from stdin golang patterns with fmt.Scan, bufio.Reader.ReadString, and bufio.Scanner. Rows like python read multiple lines from stdin are a different language; golang multiline comment syntax (/* */) is about comments, not string values—see the FAQ. For splitting typed tokens from one line, see parse multiple inputs in Go.

Checked with Go 1.24 on 64-bit Linux (Fedora and Ubuntu family).


golang multiline string literals

Raw multiline string golang (backticks)

A raw string literal uses backticks and can span lines; characters are taken literally (no \n escapes—real newlines are allowed):

go
package main

import "fmt"

func main() {
	query := `SELECT id, name
FROM users
WHERE active = true;`
	fmt.Println(query)
}
Output

You should see the SQL-shaped text printed with embedded line breaks.

Double-quoted go multiline string

Inside double quotes you use \n for newlines; the string can still be written on one source line or broken with adjacent string literals:

go
package main

import "fmt"

func main() {
	s := "line one\n" +
		"line two\n"
	fmt.Print(s)
}
Output

Backticks cannot contain a backtick; if you need one inside the text, use "..." with escapes or concatenation.


golang read stdin: multiple lines and whole stdin

fmt.Scan: tokens, not full lines

fmt.Scan splits on whitespace (newlines count as whitespace), so it is poor for golang line input that contains spaces. It fits multiple words from separate lines only when each line has a single token:

go
package main

import (
	"fmt"
	"log"
)

func main() {
	var a, b, c string
	if _, err := fmt.Scan(&a, &b, &c); err != nil {
		log.Fatal(err)
	}
	fmt.Println(a, b, c)
}
Output

Paste three whitespace-separated tokens (each line can be one word); the program prints them on one line.

bufio.Reader: ReadString and io.EOF

ReadString('\n') keeps the delimiter. Treat io.EOF when the stream ends (pipe closed or Ctrl+D on a terminal) instead of treating every error as fatal:

go
package main

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

func main() {
	fmt.Println("Enter lines; empty line ends:")
	r := bufio.NewReader(os.Stdin)
	var lines []string
	for {
		line, err := r.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				if strings.TrimSpace(line) != "" {
					lines = append(lines, line)
				}
				break
			}
			log.Fatal(err)
		}
		if strings.TrimSpace(line) == "" {
			break
		}
		lines = append(lines, line)
	}
	fmt.Println("count:", len(lines))
	for _, ln := range lines {
		fmt.Print(ln)
	}
}

Each stored line still ends with \n unless you strings.TrimSuffix it.

bufio.Scanner: idiomatic golang read line from stdin

Scanner is the usual golang read line from stdin choice: call Scan in a loop and read Text(); check Err after the loop. Tokens omit the trailing newline.

go
package main

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

func main() {
	fmt.Println("Enter lines; empty line ends:")
	sc := bufio.NewScanner(os.Stdin)
	var lines []string
	for sc.Scan() {
		line := sc.Text()
		if line == "" {
			break
		}
		lines = append(lines, line)
	}
	if err := sc.Err(); err != nil {
		log.Fatal(err)
	}
	for _, ln := range lines {
		fmt.Println(ln)
	}
}

Default Scanner token size is limited (MaxScanTokenSize); very long single lines need Buffer or a Reader.

Sentinel line instead of an empty line

End input on a line containing only q after trimming:

go
package main

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

func main() {
	sc := bufio.NewScanner(os.Stdin)
	var lines []string
	for sc.Scan() {
		line := sc.Text()
		if strings.EqualFold(strings.TrimSpace(line), "q") {
			break
		}
		lines = append(lines, line)
	}
	if err := sc.Err(); err != nil {
		log.Fatal(err)
	}
	for _, ln := range lines {
		fmt.Println(ln)
	}
}

Summary

Golang multiline string work is done in the editor with backticks or \n in quotes—unrelated to golang read stdin. For read from stdin golang programs, fmt.Scan is for whitespace-separated tokens, bufio.Reader.ReadString keeps newlines and must handle io.EOF, and bufio.Scanner is the common golang read line from stdin loop with clean Text() values and an Err check at the end. Ignore off-topic rows like python read multiple lines from stdin here, and use /* */ only when you mean a golang multiline comment, not a runtime string.


References


Frequently Asked Questions

1. How do I write a golang multiline string in source code?

Use a raw string literal in backticks for literal newlines, or a double-quoted string with \n escapes. Backticks cannot contain backticks; choose quoted strings if you need embedded quotes.

2. Is golang multiline comment the same as a multiline string?

No. Comments use /* */ or // per line. They are removed by the compiler and are not string values. This page focuses on string literals and stdin reading.

3. What is the best way to golang read line from stdin?

Prefer bufio.NewScanner(os.Stdin) with for scanner.Scan() { ... } then scanner.Err(). Scanner strips the trailing newline from each token. Use bufio.Reader.ReadString if you need to keep newline bytes or read very long lines with a custom SplitFunc.

4. Why does fmt.Scan not read a whole line with spaces?

Scan splits on whitespace, and newlines count as whitespace, so you get separate tokens—not a full line. Use bufio for line-oriented input.

5. Can I use bufio.Scanner for unlimited line length?

Default tokens are capped (bufio.MaxScanTokenSize, 64 KiB). For longer lines, scanner.Buffer or a Reader-based approach is required.
Tuan Nguyen

Data Scientist

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 …