Handling stdin in Go: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(29 intermediate revisions by the same user not shown)
Line 2: Line 2:
* [[Go_Code_Examples#Code_Examples|Go Code Examples]]
* [[Go_Code_Examples#Code_Examples|Go Code Examples]]
* [[Go Strings]]
* [[Go Strings]]
* [[Go Package fmt|<tt>fmt</tt> Package]]


=<tt>fmt.Scan()</tt>=
=Probing <tt>stdin</tt>=
 
=Handling <tt>stdin</tt> with <tt>bufio.NewReader().ReadString()</tt>=
"Command line" loop:
<syntaxhighlight lang='go'>
r := bufio.NewReader(os.Stdin)
for {
  fmt.Print("> ")
  lineb, _, err := r.ReadLine()
  if err != nil {
    return
  }
  line := string(lineb)
  if line == "exit" {
    return
  }
}
</syntaxhighlight>
Note that the string contains the trailing <code>\n</code>. You can remove it with <code>[[Go_Strings#Trim.28.29|strings.Trim()]]</code>.
 
=Handling <tt>stdin</tt> with <tt>fmt</tt> Functions=
Reading lines of input from <code>stdin</code>, as individual strings, with <code>fmt.Scan*</code> functions is somewhat inconvenient. The library seems to want to tokenize the string and store fragments into different variables. That could be a good pattern if you get used with it, but to read lines "in bulk", use <code>[[#Handling_stdin_with_bufio.NewReader.28.29.ReadString.28.29|bufio.NewReader().ReadString()]]</code>.
==<tt>fmt.Scan()</tt>==
{{External|https://golang.org/pkg/fmt/#Scan}}
Read text from <code>stdin</code>. It '''stores successive space-separated values into successive arguments'''. Newlines count as space. It returns the number of items successfully scanned. If that is less than the number of arguments, <tt>err</tt> will report why.
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
var s string
var s string
Line 9: Line 34:
fmt.Printf("input line: %s, cnt: %d, error: %s\n", s, cnt, err)
fmt.Printf("input line: %s, cnt: %d, error: %s\n", s, cnt, err)
</syntaxhighlight>
</syntaxhighlight>
=<tt>fmt.Scanf()</tt>=
 
==<tt>fmt.Scanln()</tt>==
{{External|https://golang.org/pkg/fmt/#Scanln}}
<code>Scanln</code> is similar to <code>Scan</code>, but stops scanning at a newline or EOF. It still uses space as separator, and '''stores space-separated fragments into successive arguments'''.
<syntaxhighlight lang='go'>
var line string
fmt.Scanln(&line)
</syntaxhighlight>
 
==<tt>fmt.Scanf()</tt>==
{{External|https://golang.org/pkg/fmt/#Scanf}}
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
var f float
var f float
cnt, err := fmt.Scanf("%f", &f)
cnt, err := fmt.Scanf("%f", &f)
</syntaxhighlight>
=Reading a Password from Console=
<syntaxhighlight lang='go'>
import (
"fmt"
"os"
"syscall"
"golang.org/x/term"
)
func main() {
fmt.Print("password: ")
if p, err := term.ReadPassword(int(syscall.Stdin)); err != nil {
      ...
    } else {
      pass := string(p)
      ...
    }
}
</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 20:02, 26 July 2024

Internal

Probing stdin

Handling stdin with bufio.NewReader().ReadString()

"Command line" loop:

r := bufio.NewReader(os.Stdin)
for {
  fmt.Print("> ")
  lineb, _, err := r.ReadLine()
  if err != nil {
    return
  }
  line := string(lineb)
  if line == "exit" {
    return
  }
}

Note that the string contains the trailing \n. You can remove it with strings.Trim().

Handling stdin with fmt Functions

Reading lines of input from stdin, as individual strings, with fmt.Scan* functions is somewhat inconvenient. The library seems to want to tokenize the string and store fragments into different variables. That could be a good pattern if you get used with it, but to read lines "in bulk", use bufio.NewReader().ReadString().

fmt.Scan()

https://golang.org/pkg/fmt/#Scan

Read text from stdin. It stores successive space-separated values into successive arguments. Newlines count as space. It returns the number of items successfully scanned. If that is less than the number of arguments, err will report why.

var s string
cnt, err := fmt.Scan(&s)
fmt.Printf("input line: %s, cnt: %d, error: %s\n", s, cnt, err)

fmt.Scanln()

https://golang.org/pkg/fmt/#Scanln

Scanln is similar to Scan, but stops scanning at a newline or EOF. It still uses space as separator, and stores space-separated fragments into successive arguments.

var line string
fmt.Scanln(&line)

fmt.Scanf()

https://golang.org/pkg/fmt/#Scanf
var f float
cnt, err := fmt.Scanf("%f", &f)

Reading a Password from Console

import (
	"fmt"
	"os"
	"syscall"

	"golang.org/x/term"
)

func main() {
	fmt.Print("password: ")
	if p, err := term.ReadPassword(int(syscall.Stdin)); err != nil {
       ...
    } else {
       pass := string(p)
       ...
    }
}