-3
package main
import "fmt"

func main(){
    var i int
    fmt.Print("input integer: ")
    fmt.Scanf("%d", &i)

}

when I run this small program from terminal and give input as

input integer: 3.ls

it also executes ls command or when i give input

input integer: 665.cd someDir

it executes cd someDir. Is this normal behavior with Scanf in go.This does not happen in C. Can someone explain what's happening.

vitaut
  • 49,672
  • 25
  • 199
  • 336
klv0000
  • 174
  • 10

2 Answers2

3

Not an answer, just an expansion on what @icza wrote but too big to fit into a comment.

I'd also try to shed more light at why that

does not happen in C

effect takes place.

Most probably you have used scanf(3), and the functions of its ilk operate not on file descriptors (like syscall wrappers such as read(2) and write(2)) but rather on so-called "streams" provided by the C standard library; these facilities are referred to as "stdio".

These streams provide default buffering and stdin is usually line-buffered by default.

Consider the following program:

#include <stdio.h>

int main()
{
    int rc, i;

    printf("input integer: ");

    rc = scanf("%d", &i);
    if (rc != 1) {
        perror("scan failed");
        return 1;
    }

    return 0;
}

If we build it

$ gcc -o scanf -W -Wall -Werror scanf.c

and then run "as is", we observe that the program have consumed those extra .ls characters:

$ ./scanf
input integer: 3.ls
$

Let's now see what happens when we modify the idea of the buffering to use by default of the libc linked to our program. We'll use stdbuf for that:

$ stdbuf -i 0 ./scanf
input integer: 3.ls
scanf scanf.c
$

That's why the @icza's advice works: in Go, variables form the os package which hold the file objects opened to the standard streams have no buffering as they are of type *os.File, and those are quite thin wrappers around the file descriptors returned by the OS.

If you need buffering you should explicitly use it where it belongs (and be careful about it: do not mix reads/writes on a buffering wrapper and its underlying data source/sink—at least unless you're absolutely sure what you're doing).

kostix
  • 51,517
  • 14
  • 93
  • 176
2

Your fmt.Scanf("%d", &i) call only parses an integer from the input, it does not consume input until the end of line.

If you input 3.ls, then 3 is parsed as the decimal number, and . is consumed and will stop the scanning. Your app ends here, so the rest (ls and the newline) will be executed by your shell.

Use bufio.Scanner to read lines, e.g.:

fmt.Print("input string: ")
scanner := bufio.NewScanner(os.Stdin)
if !scanner.Scan() {
    return // no input
}
var i int
fmt.Sscanf(scanner.Text(), "%d", &i)
fmt.Println("Entered:", i)

See related: Tell me what's wrong with this code GOLANG

icza
  • 389,944
  • 63
  • 907
  • 827
  • 1
    Wanted to add a comment expanding on that buffering thing but that ended up being too large for a comment. If you find that info relevant, please feel free to include it into your answer and I'll delete mine ;-) – kostix Nov 17 '20 at 16:45
  • @kostix I think it's fine as your separate answer. – icza Nov 17 '20 at 17:12