¿Cómo leer desde la entrada estándar en la consola?

270

Me gustaría leer la entrada estándar desde la línea de comando, pero mis intentos han terminado con la salida del programa antes de que se me solicite la entrada. Estoy buscando el equivalente de Console.ReadLine () en C #.

Esto es lo que tengo actualmente:

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)
}
Dante
fuente
Este código se ve correcto. Por curiosidad, ¿estás ejecutando esto en el patio de recreo? Go Playground no permite la entrada stdin debido a razones de red.
LinearZoetrope
No importa, parece ser un problema sutil en el que necesitabas un puntero (ver mi respuesta). Aunque no estoy seguro de cuál es el problema con el método bufio.NewReader, ya que funciona para mí.
LinearZoetrope
posible duplicado de Leer desde stdin inicial en GO?
anatoly techtonik 01 de
8
No mezcle el bufioalmacenamiento en búfer de ningún lector (p bufio.NewReader(os.Stdin). Ej. ) Con lecturas directas del lector subyacente (p. Ej., fmt.Scanln(x)Lecturas directas de os.Stdin). El almacenamiento en búfer puede leerse arbitrariamente más adelante (En este caso específico, lo último debería ser fmt.Fscanln(reader,x)leer desde el mismo búfer).
Dave C
No obtengo fmt.Sscanlntrabajos, se convierte en "% v" después de ejecutar
Beeno Tung

Respuestas:

295

No estoy seguro de qué le pasa al bloque

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

Como funciona en mi máquina. Sin embargo, para el siguiente bloque necesita un puntero a las variables a las que está asignando la entrada. Intenta reemplazar fmt.Scanln(text2)con fmt.Scanln(&text2). No lo use Sscanln, porque analiza una cadena que ya está en memoria en lugar de stdin. Si desea hacer algo como lo que estaba tratando de hacer, reemplácelo confmt.Scanf("%s", &ln)

Si esto aún no funciona, su culpable podría ser una configuración extraña del sistema o un IDE con errores.

LinearZoetrope
fuente
2
¿Se supone que son comillas simples? ReadString('\n')o ReadString("\n")?
425nesp
8
@ 425nesp sí, ese es el delímetro, que es un solo byte. golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope
3
Buena respuesta, pero esto falla cuando intento usar las teclas de retroceso, etc.
kumarharsh
44
Tanto para que Golang lea una línea del archivo a través del lector rda la variable scomoif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU
2
Solo compartiendo algo interesante (soy un principiante de Golang): \ n debe estar entre comillas simples (no intente usar comillas dobles). O bien, reproducirá esto:cannot use "\n" (type string) as type byte in argument to reader.ReadString
ivanleoncz
124

también puedes probar:

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

if scanner.Err() != nil {
    // handle error.
}
Helin Wang
fuente
66
Puede eliminar "for {}" si solo desea una entrada de una línea.
user2707671
3
si hay un bucle for {}, ¿cómo salir del bucle al ingresar? ¿Hay un personaje especial que hará que el bucle se detenga? - Gracias
Madhan Ganesh
2
@Madhan scanner.Scan () devuelve el valor de bool para indicar salir del bucle for o no.
Helin Wang el
55
Obtendrá este error bufio.Scanner: token demasiado largo si su entrada es mayor que 64 * 1024 bytes. Además, no olvide agregar fmt.Println(scanner.Err())debajo del bucle for.
Yuvaraj Loganathan
¿Qué sucede si ingreso "abc \ n ^ D", la cadena esperada es "abc \ n" pero devuelve "abc"?
Shivendra Mishra
96

Creo que una forma más estándar de hacer esto sería:

package main

import "fmt"

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

Eche un vistazo al scangodoc: http://godoc.org/fmt#Scan

El escaneo escanea el texto leído desde la entrada estándar, almacenando valores sucesivos separados por espacios en argumentos sucesivos. Las nuevas líneas cuentan como espacio.

Scanln es similar a Scan, pero detiene el escaneo en una nueva línea y después del elemento final debe haber una nueva línea o EOF.

Médula
fuente
10
Esto no parece gustarle espacios en la cadena de entrada.
Peludo Chris
3
@HairyChris sí, esto es extraño. En el documento dice que stops scanning at a newline and after the final item there must be a newline or EOFno estoy seguro de por qué el espacio lo "rompe" ... Supongo que es un error
karantan
66
Se abrió un error para esto: github.com/golang/go/issues/5703 Se cerró como WorkingAsIntended. Consulte también: stackoverflow.com/questions/24005899/… y groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Parece que muchas personas tienen problemas con esto. ¿Se necesita un cambio de documentación? Además, desde ese último enlace: "Scan y Scanln son para analizar y cosas así, por lo que simplemente obtener una sola línea de texto de stdin sería contrario al propósito".
user2707671
Para mí, es realmente confuso que fmt.Scan en cualquiera de sus funciones similares no juegue bien con espacios como el bufio.NewReader sí.
FilBot3
3
El mismo problema con los espacios permanece mientras se usa fmt.Scanlny fmt.Scancon la versión actual de 2016 go (versión go go 1.6.6 linux / amd64).
Chiheb Nexus
30

Siempre trate de usar el bufio.NewScanner para recopilar información de la consola. Como otros mencionaron, hay varias formas de hacer el trabajo, pero Scanner originalmente está destinado a hacer el trabajo. Dave Cheney explica por qué debería usar Scanner en lugar de bufio. ReadLine de Read.

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

Aquí está la respuesta del fragmento de código para su pregunta

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)
}

Si no desea recopilar las entradas mediante programación, simplemente agregue estas líneas

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

La salida del programa anterior será:

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

El programa anterior recopila la entrada del usuario y la guarda en una matriz. También podemos romper ese flujo con un carácter especial. Scanner proporciona API para uso avanzado como dividir usando una función personalizada, etc., escaneando diferentes tipos de flujos de E / S (Stdin, String), etc.

Naren Yellavula
fuente
Esta debería ser la respuesta aceptada. No solo es una respuesta más precisa sino que es de mejor calidad.
Daniel Farrell
11

Otra forma de leer múltiples entradas dentro de un bucle que puede manejar una entrada con espacios:

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)
        }
    }
}

Salida:

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
fuente
2
Tal vez podría usar una pausa en la comprobación interna "q" y envolverlo todo en un bucle infinito. Gran respuesta por cierto!
tebanep
2
Parece que ahora también puedes deshacerte del condicional en el ciclo for.
irbanana
6

Llego tarde a la fiesta. Pero ¿qué tal un trazador de líneas:

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

y presione ctrl + d (EOT) una vez que se ingresa la entrada en la línea de comando.

Shivendra Mishra
fuente
Porque os.Stdinno 'termina' es imposible leerlo todo. Puede que
estés
2
presione ctrl + d, es decir, eot.
Shivendra Mishra
3
Sí, eso lo haría, me recuerda escribir correos electrónicos con mail.
gypsydave5
5

Prueba este código: -

var input string
func main() {
      fmt.Print("Enter Your Name=")
      fmt.Scanf("%s",&input)
      fmt.Println("Hello "+input)
      }
Shivam Sharma
fuente
3
Parece Scanf()que no acepta espacios en blanco en cadena
Eslam
4

También se puede hacer así:

package main
import "fmt"     

func main(){
    var myname string
fmt.Scanf("%s", &myname)           
fmt.Println("Hello", myname)       
}
Nitin yadav
fuente
3

Lea claramente en un par de valores solicitados:

// 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))

Aquí hay una carrera:

Enter text: Jim
Enter More text: Susie
Text1: "Jim", Text2: "Susie"
Rohanthewiz
fuente
2
También es una buena manera desde cadenas. TrimSpace elimina el '\ n'. Y creo lector.ReadString ('\ n') también es multiplataforma.
user2707671
Supongo que la mayoría de las veces quieres eliminar \ n de forma predeterminada, es por eso que es mejor bufio.NewScanner como @Naren Yellavula responde
John Balvin Arias
2

Debe proporcionar un puntero a la var que desea escanear, así:

fmt.scan(&text2)
Liam Mertens
fuente
0

En mi caso, el programa no estaba esperando porque estaba usando el watchercomando para ejecutar automáticamente el programa. La ejecución manual del programa go run main.godio como resultado "Introducir texto" y, finalmente, imprimir en la consola.

fmt.Print("Enter text: ")
var input string
fmt.Scanln(&input)
fmt.Print(input)
Sol R
fuente
2
La limitación de la Scan*familia es que leen hasta un separador de espacios en blanco (por ejemplo, espacios).
George Tseres