Estoy tratando de hacer algunos de los desafíos del código de golf , pero todos requieren que se tome la entrada stdin
. ¿Cómo consigo eso en Python?
Estoy tratando de hacer algunos de los desafíos del código de golf , pero todos requieren que se tome la entrada stdin
. ¿Cómo consigo eso en Python?
Respuestas:
Podrías usar el fileinput
módulo:
import fileinput
for line in fileinput.input():
pass
fileinput
recorrerá todas las líneas en la entrada especificada como nombres de archivo dados en argumentos de línea de comandos, o la entrada estándar si no se proporcionan argumentos.
Nota: line
contendrá una nueva línea final; para eliminarlo useline.rstrip()
Hay algunas formas de hacerlo.
sys.stdin
es un objeto similar a un archivo en el que puede llamar funciones read
o readlines
si desea leer todo o si desea leer todo y dividirlo por nueva línea automáticamente. (Es necesario que import sys
esto funcione).
Si desea solicitar al usuario una entrada, puede usarla raw_input
en Python 2.X y solo input
en Python 3.
Si en realidad solo desea leer las opciones de la línea de comandos, puede acceder a ellas a través de la lista sys.argv .
Probablemente encontrará que este artículo de Wikibook sobre E / S en Python también es una referencia útil.
import sys
for line in sys.stdin:
print(line)
Tenga en cuenta que esto incluirá un carácter de nueva línea al final. Para eliminar la nueva línea al final, use line.rstrip()
como dijo @brittohalloran.
\r\n
los finales de línea
Python también tiene funciones integradas input()
y raw_input()
. Consulte la documentación de Python en Funciones incorporadas .
Por ejemplo,
name = raw_input("Enter your name: ") # Python 2.x
o
name = input("Enter your name: ") # Python 3
Aquí está de Learning Python :
import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."
En Unix, puede probarlo haciendo algo como:
% cat countlines.py | python countlines.py
Counted 3 lines.
En Windows o DOS, harías:
C:\> type countlines.py | python countlines.py
Counted 3 lines.
print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), '')))
. verwc-l.py
cat
aquí es redundante. La invocación correcta para sistemas Unix es python countlines.py < countlines.py
.
readlines()
. Los objetos de archivo están destinados a ser iterados sin materializar todos los datos en la memoria.
¿Cómo se lee desde stdin en Python?
Estoy tratando de hacer algunos de los desafíos del código de golf, pero todos requieren que la entrada se tome de stdin. ¿Cómo consigo eso en Python?
Puedes usar:
sys.stdin
- Un objeto similar a un archivo: llame sys.stdin.read()
para leer todo.input(prompt)
- pásele un mensaje opcional para generar, lee desde stdin hasta la primera línea nueva, que elimina. Tendría que hacer esto repetidamente para obtener más líneas, al final de la entrada aumenta EOFError. (Probablemente no es genial para jugar al golf.) En Python 2, esto es rawinput(prompt)
.open(0).read()
- En Python 3, la función incorporada open
acepta descriptores de archivo (enteros que representan recursos de E / S del sistema operativo) y 0 es el descriptor de stdin
. Devuelve un objeto similar a un archivo sys.stdin
, probablemente su mejor apuesta para jugar al golf. En Python 2, esto es io.open
.open('/dev/stdin').read()
- similar a open(0)
, funciona en Python 2 y 3, pero no en Windows (o incluso Cygwin).fileinput.input()
- devuelve un iterador sobre líneas en todos los archivos enumerados sys.argv[1:]
, o stdin si no se proporciona. Utilizar como ''.join(fileinput.input())
.Ambos sys
y fileinput
deben importarse, respectivamente, por supuesto.
sys.stdin
Ejemplos rápidos compatibles con Python 2 y 3, Windows, UnixSólo tiene que read
partir sys.stdin
, por ejemplo, si los datos de tubería a la entrada estándar:
$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo
Podemos ver que sys.stdin
está en modo de texto predeterminado:
>>> import sys
>>> sys.stdin
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
Digamos que tiene un archivo, inputs.txt
podemos aceptar ese archivo y volver a escribirlo:
python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
Aquí hay una demostración completa, fácilmente replicable, usando dos métodos, la función incorporada, input
(uso raw_input
en Python 2) y sys.stdin
. Los datos no se modifican, por lo que el procesamiento no funciona.
Para empezar, creemos un archivo para entradas:
$ python -c "print('foo\nbar\nbaz')" > inputs.txt
Y usando el código que ya hemos visto, podemos verificar que hemos creado el archivo:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Aquí está la ayuda sys.stdin.read
de Python 3:
read(size=-1, /) method of _io.TextIOWrapper instance
Read at most n characters from stream.
Read from underlying buffer until we have n characters or we hit EOF.
If n is negative or omitted, read until EOF.
input
( raw_input
en Python 2)La función incorporada input
lee desde la entrada estándar hasta una nueva línea, que se elimina (complementando print
, lo que agrega una nueva línea por defecto). Esto ocurre hasta que obtiene EOF (Fin del archivo), momento en el que se eleva EOFError
.
Por lo tanto, así es como puede usar input
en Python 3 (o raw_input
en Python 2) para leer desde stdin, por lo que creamos un módulo de Python que llamamos stdindemo.py:
$ python -c "print('try:\n while True:\n print(input())\nexcept EOFError:\n pass')" > stdindemo.py
Y imprimámoslo nuevamente para asegurarnos de que es como esperamos:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py
try:
while True:
print(input())
except EOFError:
pass
Nuevamente, input
lee hasta la nueva línea y esencialmente la elimina de la línea. print
agrega una nueva línea. Entonces, mientras ambos modifican la entrada, sus modificaciones se cancelan. (Por lo tanto, son esencialmente el complemento del otro).
Y cuando input
obtiene el carácter de fin de archivo, genera EOFError, que ignoramos y luego salimos del programa.
Y en Linux / Unix, podemos canalizar desde cat:
$ cat inputs.txt | python -m stdindemo
foo
bar
baz
O simplemente podemos redirigir el archivo desde stdin:
$ python -m stdindemo < inputs.txt
foo
bar
baz
También podemos ejecutar el módulo como un script:
$ python stdindemo.py < inputs.txt
foo
bar
baz
Aquí está la ayuda sobre la construcción input
de Python 3:
input(prompt=None, /)
Read a string from standard input. The trailing newline is stripped.
The prompt string, if given, is printed to standard output without a
trailing newline before reading input.
If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
On *nix systems, readline is used if available.
sys.stdin
Aquí hacemos un script de demostración usando sys.stdin
. La forma eficiente de iterar sobre un objeto similar a un archivo es usar el objeto similar a un archivo como iterador. El método complementario para escribir en stdout desde esta entrada es simplemente usar sys.stdout.write
:
$ python -c "print('import sys\nfor line in sys.stdin:\n sys.stdout.write(line)')" > stdindemo2.py
Imprima de nuevo para asegurarse de que se ve bien:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py
import sys
for line in sys.stdin:
sys.stdout.write(line)
Y redirigiendo las entradas al archivo:
$ python -m stdindemo2 < inputs.txt
foo
bar
baz
Golfed en un comando:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Dado que los descriptores de archivo para stdin
y stdout
son 0 y 1 respectivamente, también podemos pasarlos a open
Python 3 (no a 2, y tenga en cuenta que todavía necesitamos la 'w' para escribir en stdout).
Si esto funciona en su sistema, eliminará más caracteres.
$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo
Python 2 también io.open
hace esto, pero la importación ocupa mucho más espacio:
$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt
foo
bar
baz
Un comentario sugiere ''.join(sys.stdin)
para jugar al golf, pero en realidad es más largo que sys.stdin.read (); además, Python debe crear una lista adicional en la memoria (así es como str.join
funciona cuando no se le da una lista), por contraste:
''.join(sys.stdin)
sys.stdin.read()
La respuesta principal sugiere:
import fileinput
for line in fileinput.input():
pass
Pero, dado que sys.stdin
implementa la API de archivo, incluido el protocolo de iterador, es lo mismo que esto:
import sys
for line in sys.stdin:
pass
Otra respuesta no sugiere esto. Sólo recuerde que si lo hace en un intérprete, usted tiene que hacer Ctrl- dsi estás en Linux o Mac, o Ctrl- zen Windows (después Enter) para enviar el carácter de fin de archivo en el proceso. Además, esa respuesta sugiere print(line)
, que agrega una '\n'
al final, usar print(line, end='')
en su lugar (si en Python 2, necesitará from __future__ import print_function
).
El caso de uso real fileinput
es para leer en una serie de archivos.
La respuesta propuesta por otros:
for line in sys.stdin:
print line
es muy simple y pitónico, pero debe tenerse en cuenta que el script esperará hasta EOF antes de comenzar a iterar en las líneas de entrada.
Esto significa que tail -f error_log | myscript.py
no procesará líneas como se esperaba.
El script correcto para tal caso de uso sería:
while 1:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
print line
ACTUALIZACIÓN
De los comentarios se ha aclarado que en python 2 solo puede haber un búfer involucrado, por lo que terminará esperando que se llene el búfer o EOF antes de que se emita la llamada de impresión.
for line in sys.stdin:
patrón no espera EOF. Pero si prueba en archivos muy pequeños, las respuestas se pueden almacenar. Pruebe con más datos para ver que lee resultados intermedios.
print line
no se despertó en 3.1.3, pero print(line)
sí.
for line in sys.stdin:
no "bloquea hasta EOF". Hay un error de lectura anticipada en Python 2 que retrasa las líneas hasta que el búfer correspondiente esté lleno. Es un problema de almacenamiento en búfer que no está relacionado con EOF. Para solucionarlo, use for line in iter(sys.stdin.readline, ''):
(use io.open()
para archivos ordinarios). No lo necesitas en Python 3.
Sobre la base de todas las respuestas usando sys.stdin
, también puede hacer algo como lo siguiente para leer desde un archivo de argumentos si existe al menos un argumento, y recurrir a stdin de lo contrario:
import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
for line in f:
# Do your stuff
y úsalo como
$ python do-my-stuff.py infile.txt
o
$ cat infile.txt | python do-my-stuff.py
o incluso
$ python do-my-stuff.py < infile.txt
Eso haría que su script Python se comportara como muchos programas GNU / Unix como cat
, grep
y sed
.
argparse
es una solución fácilEjemplo compatible con las versiones 2 y 3 de Python:
#!/usr/bin/python
import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument('infile',
default=sys.stdin,
type=argparse.FileType('r'),
nargs='?')
args = parser.parse_args()
data = args.infile.read()
Puede ejecutar este script de muchas maneras:
1. Usando stdin
echo 'foo bar' | ./above-script.py
o más corto reemplazando echo
por cadena aquí :
./above-script.py <<< 'foo bar'
2. Usando un argumento de nombre de archivo
echo 'foo bar' > my-file.data
./above-script.py my-file.data
3. Usando a stdin
través del nombre de archivo especial-
echo 'foo bar' | ./above-script.py -
add_argument('--in'
y luego canalizar al script y agregarlo --in -
a la línea de comando. PS in
no es un muy buen nombre para una variable / atributo.
in
no es solo un mal nombre para una variable, es ilegal. args.in.read()
generará un error InvalidSyntax debido a la in
palabra clave reservada. Simplemente puede cambiar el nombre para infile
gustar los documentos de discusión de python do: docs.python.org/3/library/…
El siguiente chip de código lo ayudará (leerá todo el bloqueo de stdin EOF
en una sola cadena):
import sys
input_str = sys.stdin.read()
print input_str.split()
Estoy bastante sorprendido de que nadie haya mencionado este truco hasta ahora:
python -c "import sys; set(map(sys.stdout.write,sys.stdin))"
en python2 puede soltar la set()
llamada, pero sería de cualquier manera
readlines
esa división en líneas y luego join
otra vez? Puedes escribirprint(sys.stdin.read())
write
regresa None
, y el tamaño establecido nunca sería mayor que 1 ( =len(set([None]))
)
Puede leer desde stdin y luego almacenar entradas en "datos" de la siguiente manera:
data = ""
for line in sys.stdin:
data += line
data = sys.stdin.read()
sin el problema de las concatenaciones de cadenas repetidas.
Leer desde sys.stdin
, pero para leer datos binarios en Windows , debe tener mucho cuidado, ya sys.stdin
que se abre en modo texto y se dañará al \r\n
reemplazarlos \n
.
La solución es establecer el modo en binario si se detecta Windows + Python 2, y en Python 3 usar sys.stdin.buffer
.
import sys
PY3K = sys.version_info >= (3, 0)
if PY3K:
source = sys.stdin.buffer
else:
# Python 2 on Windows opens sys.stdin in text mode, and
# binary data that read from it becomes corrupted on \r\n
if sys.platform == "win32":
# set sys.stdin to binary mode
import os, msvcrt
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
source = sys.stdin
b = source.read()
Uso el siguiente método, devuelve una cadena de stdin (lo uso para el análisis json). Funciona con pipe y prompt en Windows (aún no se ha probado en Linux). Cuando se le solicita, dos saltos de línea indican el final de la entrada.
def get_from_stdin():
lb = 0
stdin = ''
for line in sys.stdin:
if line == "\n":
lb += 1
if lb == 2:
break
else:
lb = 0
stdin += line
return stdin
El problema que tengo con la solucion
import sys
for line in sys.stdin:
print(line)
es que si no pasa ningún dato a stdin, se bloqueará para siempre. Es por eso que me encanta esta respuesta : primero verifique si hay algunos datos en stdin y luego léala. Esto es lo que terminé haciendo:
import sys
import select
# select(files to read from, files to write to, magic, timeout)
# timeout=0.0 is essential b/c we want to know the asnwer right away
if select.select([sys.stdin], [], [], 0.0)[0]:
help_file_fragment = sys.stdin.read()
else:
print("No data passed to stdin", file=sys.stderr)
sys.exit(2)
select
se llama; o también podría enfrentar problemas si stdin está conectado a un archivo en un medio lento (red, CD, cinta, etc.). Dijiste que "si no pasas ningún dato a stdin, se bloqueará para siempre". es un problema , pero yo diría que es una característica . La mayoría de los programas CLI (por ejemplo cat
) funcionan de esta manera, y se espera que lo hagan. EOF es lo único en lo que debe depender para detectar el final de la entrada.
Tuve algunos problemas al hacer que esto funcionara para leer sobre sockets conectados a él. Cuando el zócalo se cerró, comenzó a devolver una cadena vacía en un bucle activo. Así que esta es mi solución (que solo probé en Linux, pero espero que funcione en todos los demás sistemas)
import sys, os
sep=os.linesep
while sep == os.linesep:
data = sys.stdin.readline()
sep = data[-len(os.linesep):]
print '> "%s"' % data.strip()
Entonces, si comienza a escuchar en un socket, funcionará correctamente (por ejemplo, en bash):
while :; do nc -l 12345 | python test.py ; done
Y puede llamarlo con telnet o simplemente apuntar un navegador a localhost: 12345
Con respecto a este:
for line in sys.stdin:
Acabo de probarlo en Python 2.7 (siguiendo la sugerencia de otra persona) para un archivo muy grande, y no lo recomiendo, precisamente por las razones mencionadas anteriormente (no pasa nada durante mucho tiempo).
Terminé con una solución un poco más pitónica (y funciona en archivos más grandes):
with open(sys.argv[1], 'r') as f:
for line in f:
Entonces puedo ejecutar el script localmente como:
python myscript.py "0 1 2 3 4..." # can be a multi-line string or filename - any std.in input will work
sys.stdin
como argumento de línea de comandos al script.
sys.stdin
como un argumento de línea de comandos al script? Los argumentos son cadenas y las secuencias son objetos en forma de archivo, no son lo mismo.
sys.stdin
es un objeto similar a un archivo
Para Python 3 eso sería:
# Filename e.g. cat.py
import sys
for line in sys.stdin:
print(line, end="")
Esta es básicamente una forma simple de cat (1), ya que no agrega una nueva línea después de cada línea. Puede usar esto (después de haber marcado el archivo ejecutable usando chmod +x cat.py
:
echo Hello | ./cat.py
Al usar el -c
comando, como una forma complicada, en lugar de leer el stdin
(y más flexible en algunos casos), también puede pasar un comando de script de shell a su comando de Python poniendo el comando de venta entre comillas dentro de un paréntesis que comienza con un $
signo.
p.ej
python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"
Esto contará el número de líneas del archivo histórico de goldendict.