In Go, can a single line of input be read from stdin in a simple way, which also meets the following requirements?
- can be called by disparate parts of a larger interactive application without having to create coupling between these different parts of the application (e.g. by passing a global
bufio.Scanner
between them) - works whether users are running an interactive terminal or using pre-scripted input
I'd like to modify an existing large Go application which currently creates a bufio.Scanner
instance every time it asks users for a line of input. Multiple instances work fine when standard input is from a terminal, but when standard input is piped from another process, calls to Scan
only succeed on the first instance of bufio.Scanner
. Calls from all other instances fail.
Here's some toy code that demonstrates the problem:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// read with 1st scanner -> works for both piped stdin and terminal
scanner1 := readStdinLine(1)
// read with 2nd scanner -> fails for piped stdin, works for terminal
readStdinLine(2)
// read with 1st scanner -> prints line 2 for piped stdin, line 3 for terminal
readLine(scanner1, 3)
}
func readStdinLine(lineNum int64) (scanner *bufio.Scanner) {
scanner = readLine(bufio.NewScanner(os.Stdin), lineNum)
return
}
func readLine(scannerIn *bufio.Scanner, lineNum int64) (scanner *bufio.Scanner) {
scanner = scannerIn
scanned := scanner.Scan()
fmt.Printf("%d: ", lineNum)
if scanned {
fmt.Printf("Text=%s
", scanner.Text())
return
}
if scanErr := scanner.Err(); scanErr != nil {
fmt.Printf("Error=%s
", scanErr)
return
}
fmt.Println("EOF")
return
}
I build this as print_stdin
and run interactively from a bash shell:
~$ ./print_stdin
ab
1: Text=ab
cd
2: Text=cd
ef
3: Text=ef
But if I pipe in the text, the second bufio.Scanner
fails:
~$ echo "ab
> cd
> ef" | ./print_stdin
1: Text=ab
2: EOF
3: Text=cd