379

I would like to read standard input from the command line, but my attempts have ended with the program exiting before I'm prompted for input. I'm looking for the equivalent of Console.ReadLine() in C#.

This is what I currently have:

package main

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

func main() {
    reader := bufio.NewReader(os.Stdin)
    fmt.Print("Enter text: ")
    text, _ := reader.ReadString('\n')
    fmt.Println(text)

    fmt.Println("Enter text: ")
    text2 := ""
    fmt.Scanln(text2)
    fmt.Println(text2)

    ln := ""
    fmt.Sscanln("%v", ln)
    fmt.Println(ln)
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dante
  • 10,722
  • 16
  • 51
  • 63
  • This code looks correct. Out of curiosity, are you running this on the Playground? The Go Playground doesn't allow stdin input due to networking reasons. – Linear Jan 03 '14 at 02:34
  • Nevermind, it looks to be a subtle issue where you needed a pointer (see my answer). Though I'm not sure what the problem with the bufio.NewReader method is since it works for me. – Linear Jan 03 '14 at 02:44
  • possible duplicate of [Read from initial stdin in GO?](http://stackoverflow.com/questions/12363030/read-from-initial-stdin-in-go) – anatoly techtonik Feb 01 '15 at 19:49
  • 11
    Don't mix `bufio` buffering of any reader (e.g. `bufio.NewReader(os.Stdin)`) with direct reads from the underlining reader (e.g. `fmt.Scanln(x)` directly reads from `os.Stdin`). Buffering may read arbitrarily far ahead. (In this specific case the later should be `fmt.Fscanln(reader,x)` to read from the same buffer). – Dave C Jul 02 '15 at 14:05
  • I don't get `fmt.Sscanln` works, it becomes "%v" after running – Beeno Tung Jan 08 '18 at 04:39

12 Answers12

411

I'm not sure what's wrong with the block

reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
fmt.Println(text)

As it works on my machine. However, for the next block you need a pointer to the variables you're assigning the input to. Try replacing fmt.Scanln(text2) with fmt.Scanln(&text2). Don't use Sscanln, because it parses a string already in memory instead of from stdin. If you want to do something like what you were trying to do, replace it with fmt.Scanf("%s", &ln)

If this still doesn't work, your culprit might be some weird system settings or a buggy IDE.

Linear
  • 21,074
  • 4
  • 59
  • 70
  • You're right! I'm using GoSublime on Windows and it doesn't work there, but does on the command prompt after switching to string pointers. The weird thing is, bufio.NewReader(os.Stdin) didn't work on command prompt before either. – Dante Jan 03 '14 at 02:54
  • 3
    Are those supposed to be single quotes? `ReadString('\n')` or `ReadString("\n")`? – 425nesp Jul 16 '14 at 18:42
  • 12
    @425nesp yes, that's the delimeter, which is a single byte. http://golang.org/pkg/bufio/#Reader.ReadString – Linear Jul 17 '14 at 05:59
  • 3
    Good answer, but this fails when I try using backspace, etc keys – kumarharsh Feb 16 '17 at 08:33
  • 5
    So much for Golang to read a line from file via reader `rd` to variable `s` as `if s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }` – Nam G VU Sep 27 '17 at 10:20
  • 4
    Just sharing an interesting thing (I'm a Golang beginner): \n must be inside single quotes (don't try to use double quotes). Or else, it'll reproduce this: `cannot use "\n" (type string) as type byte in argument to reader.ReadString` – ivanleoncz Dec 03 '18 at 02:56
  • 2
    apparently `text` will have a trailing `↵` if you do this. – Khoi Aug 25 '19 at 09:05
  • buggy IDE was my case or live-reload package called air – Javohir Mirzo Fazliddinov Aug 13 '21 at 09:12
167

You can as well try:

scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

if scanner.Err() != nil {
    // Handle error.
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Helin Wang
  • 4,002
  • 1
  • 30
  • 34
129

I think a more standard way to do this would be:

package main

import "fmt"

func main() {
    fmt.Print("Enter text: ")
    var input string
    fmt.Scanln(&input)
    fmt.Print(input)
}

Take a look at the scan godoc: http://godoc.org/fmt#Scan

Scan scans text read from standard input, storing successive space-separated values into successive arguments. Newlines count as space.

Scanln is similar to Scan, but stops scanning at a newline and after the final item there must be a newline or EOF.

Community
  • 1
  • 1
Pith
  • 3,706
  • 3
  • 31
  • 44
  • 28
    This doesn't seem to like spaces in the input string. – xxx Aug 16 '15 at 20:40
  • 4
    @HairyChris yes this is strange. In the doc it says that `stops scanning at a newline and after the final item there must be a newline or EOF` so not sure why space "breaks" it... I guess it is a bug – karantan Dec 19 '15 at 10:58
  • 9
    There was a bug opened for this: https://github.com/golang/go/issues/5703 It got closed as WorkingAsIntended. See also: http://stackoverflow.com/questions/24005899/fmt-scanln-expected-newline-error and https://groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Seems a lot of people have issues with this. Documentation change needed? Also, from that last link: "Scan and Scanln are for parsing and stuff like that, so just getting a single line of text from stdin would defeat the purpose." – user2707671 Jan 04 '16 at 15:37
  • To me, its really confusing that fmt.Scan in any of its similar functions don't play well with spaces like the bufio.NewReader does. – FilBot3 Jan 12 '16 at 22:04
  • 3
    The same problem with spaces remains while using `fmt.Scanln` and `fmt.Scan` with the current 2016 go version (go version go1.6.2 linux/amd64). – Chiheb Nexus Nov 20 '16 at 16:45
  • This is intentional, fmt.Scan() and other similar functions take in as many addresses (arguments) as space separated values inputted – Jonathan Nov 07 '20 at 07:15
79

Always try to use the bufio.NewScanner for collecting input from the console. As others mentioned, there are multiple ways to do the job, but Scanner is originally intended to do the job. Dave Cheney explains why you should use Scanner instead of bufio.Reader's ReadLine.

https://twitter.com/davecheney/status/604837853344989184?lang=en

Here is the code snippet answer for your question

package main

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

/*
 Three ways of taking input
   1. fmt.Scanln(&input)
   2. reader.ReadString()
   3. scanner.Scan()

   Here we recommend using bufio.NewScanner
*/

func main() {
    // To create dynamic array
    arr := make([]string, 0)
    scanner := bufio.NewScanner(os.Stdin)
    for {
        fmt.Print("Enter Text: ")
        // Scans a line from Stdin(Console)
        scanner.Scan()
        // Holds the string that scanned
        text := scanner.Text()
        if len(text) != 0 {
            fmt.Println(text)
            arr = append(arr, text)
        } else {
            break
        }

    }
    // Use collected inputs
    fmt.Println(arr)
}

If you don't want to programmatically collect the inputs, just add these lines

   scanner := bufio.NewScanner(os.Stdin)
   scanner.Scan()
   text := scanner.Text()
   fmt.Println(text)

The output of above program will be:

Enter Text: Bob
Bob
Enter Text: Alice
Alice
Enter Text:
[Bob Alice]

The above program collects the user input and saves them to an array. We can also break that flow with a special character. Scanner provides API for advanced usage like splitting using a custom function, etc., scanning different types of I/O streams (standard Stdin, String), etc.

Edit: The tweet linked in original post is not accesible. But, one can find official reference of using Scanner from this standard library documentation: https://pkg.go.dev/bufio@go1.17.6#example-Scanner-Lines

Naren Yellavula
  • 7,273
  • 2
  • 29
  • 23
  • 1
    This should be the accepted answer. Not only is it a more accurate answer but it's of better quality. – erik258 Jan 15 '20 at 05:01
  • This is so much better than the other input methods. – Ann Kilzer Jul 02 '20 at 07:43
  • so, you shall use `scanner.Scan()` prior to `scanner.Text()` that is mandatory in order to parse the input for stdin ending with an enter `\n`, right? – Victor Jul 20 '20 at 13:15
  • 2
    @Victor, yes. If you read through the official bufio docs, "Text returns the most recent token generated by a call to Scan as a newly allocated string holding its bytes." which exactly answers your question. https://golang.org/pkg/bufio/#Scanner.Text – Naren Yellavula Jul 21 '20 at 07:55
  • 1
    Thanks @NarenYellavula. I do wonder why they provide both functions by seperated instead of aggregate then (in the right order) into a another abstraction, e.g.: ReadLine() (see this example: https://play.golang.org/p/cR8XjJ6WHtq). Another question regarding my thoughts is... what is the motivation of using Scan() without Text() or Bytes()? You see, a wise thing to do is if two things goes together (Scan + Text) why don't put then together into a single abstraction. – Victor Jul 21 '20 at 17:27
16

Another way to read multiple inputs within a loop which can handle an input with spaces:

package main
import (
    "fmt"
    "bufio"
    "os"
)

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    var text string
    for text != "q" {  // break the loop if text == "q"
        fmt.Print("Enter your text: ")
        scanner.Scan()
        text = scanner.Text()
        if text != "q" {
            fmt.Println("Your text was: ", text)
        }
    }
}

Output:

Enter your text: Hello world!
Your text was:  Hello world!
Enter your text: Go is awesome!
Your text was:  Go is awesome!
Enter your text: q
Chiheb Nexus
  • 9,104
  • 4
  • 30
  • 43
  • 2
    You could maybe just use a break in the inner "q" check and wrap it all in an infinite loop. Great answer by the way! – tebanep Nov 23 '16 at 20:29
  • 2
    Looks like you can also get rid of the conditional in the for loop now too. – irbanana Apr 19 '18 at 08:20
11

It can also be done like this:

package main
import "fmt"

func main(){
    var myname string
    fmt.Scanf("%s", &myname)
    fmt.Println("Hello", myname)
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nitin yadav
  • 194
  • 2
  • 8
9

I'm late to the party. But how about one liner:

data, err := io.ReadAll(os.Stdin)

And press ctrl+d once done.

Shivendra Mishra
  • 638
  • 4
  • 25
5

Cleanly read in a couple of prompted values:

// Create a single reader which can be called multiple times
reader := bufio.NewReader(os.Stdin)
// Prompt and read
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
fmt.Print("Enter More text: ")
text2, _ := reader.ReadString('\n')
// Trim whitespace and print
fmt.Printf("Text1: \"%s\", Text2: \"%s\"\n",
    strings.TrimSpace(text), strings.TrimSpace(text2))

Here's a run:

Enter text: Jim
Enter More text: Susie
Text1: "Jim", Text2: "Susie"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rohanthewiz
  • 947
  • 9
  • 9
  • 2
    Also a nice way since strings.TrimSpace removes the '\n'. And I believe reader.ReadString('\n') is cross platform too. – user2707671 Jan 04 '16 at 14:27
  • I'll guess that most of the time you want to remove \n by default, that it's why it is better bufio.NewScanner as @Naren Yellavula answer – John Balvin Arias Sep 01 '18 at 22:37
5

Try this code:

var input string
func main() {
    fmt.Print("Enter Your Name=")
    fmt.Scanf("%s", &input)
    fmt.Println("Hello " + input)
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shivam Sharma
  • 290
  • 2
  • 14
5

You need to provide a pointer to the variable you want to scan, like so:

fmt.scan(&text2)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Liam Mertens
  • 61
  • 1
  • 1
3

In my case, the program was not waiting because I was using the watcher command to auto run the program. Manually running the program go run main.go resulted in "Enter text" and eventually printing to the console.

fmt.Print("Enter text: ")
var input string
fmt.Scanln(&input)
fmt.Print(input)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
R Sun
  • 1,353
  • 14
  • 17
0

Let's do it very simple

s:=""
b := make([]byte, 1)
for os.Stdin.Read(b) ; b[0]!='\n'; os.Stdin.Read(b) {
    s+=string(b)
}
fmt.Println(s)
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245