Scanf值作为终端中的命令执行

时间:2018-06-16 08:32:42

标签: go

我有简单的程序可以将里程转换为公里数:

const kmInMile = 1.609344

func main() {
    var miles float64

    fmt.Print("Enter miles: ")
    fmt.Scanf("%f", &miles)

    fmt.Println(miles)

    km := kmInMile * miles

    fmt.Println(miles, "miles =", km, "km")
}

如果我将“lls”作为scanf的输入传递:

Enter miles: lls

输出是:

0
0 miles = 0 km
alexandrkrivosheev$ ls
hello   main.go

所以输入了第一个字符,其他所有字符都是作为命令执行。 为什么会发生这种情况?如何防止这种情况发生?

完整终端会议:

alexandrkrivosheev$ ./hello 
Enter miles: lls
0
0 miles = 0 km
alexandrkrivosheev$ ls
hello   main.go
alexandrkrivosheev$ 

1 个答案:

答案 0 :(得分:4)

使用“plain fmt.Scanf”时,输入必须与预期的格式匹配,即在您的情况下,它必须是有效的float。如果不是则则中止扫描并且输入的其余部分保留在控制台的输入缓冲区中,在程序退出后将其作为下一个命令执行。

要解决此问题,请将标准输入包装成bufio.Readerbufio.Scanner

func main() {
    var miles float64

    fmt.Print("Enter miles: ")
    //
    reader := bufio.NewReader(os.Stdin)
    val, err := reader.ReadString('\n')
    if err != nil {
        fmt.Println(err)
        return
    }
    if _, err = fmt.Sscanf(val, "%f", &miles); err != nil {
        fmt.Println(val, err)
        return
    }

    fmt.Println(miles)

    km := kmInMile * miles

    fmt.Println(miles, "miles =", km, "km")
}

这样您就可以从输入中消耗整行并单独处理它。