Pregunta

Esta pregunta ya tiene respuesta aquí:

Para mi propia diversión, he preparado un script en Python que me permite usar Python para frases ingeniosas de bash;Proporcione una expresión generadora de Python;y el script lo itera.Aquí está el guión:

DEFAULT_MODULES = ['os', 're', 'sys']

_g = {}
for m in DEFAULT_MODULES:
    _g[m] = __import__(m)

import sys
sys.stdout.writelines(eval(sys.argv[1], _g))

Y así es como puedes usarlo.

$ groups | python pype.py '(l.upper() for l in sys.stdin)'
DBORNSIDE
$ 

Para el uso previsto, ¡funciona perfectamente!

Pero cuando no lo alimento con pipe y simplemente lo invoco directamente, por ejemplo: [énfasis añadido para mostrar lo que escribo]

$ python pype.py '("%r\n" % (l,) for l in sys.stdin)'
fooIngresarbarIngresarbazIngresar
CtrlDCtrlD'foo\n'
'bar\n'
'baz\n'
$ 

Para dejar de aceptar entradas y producir resultados, tengo que escribir Ingresar - CtrlD - CtrlD o CtrlD - CtrlD - CtrlD.Esto viola mis expectativas de que cada línea debe procesarse tal como se ingresó y que escribir CtrlD En cualquier momento finalizará el guión.¿Dónde está la brecha en mi comprensión?

EDITAR:Actualicé el ejemplo interactivo para mostrar que no veo las citas que Wim describe en su respuesta, y también algunos ejemplos más.

$ python pype.py '("%r\n" % (l,) for l in sys.stdin)'
fooCtrlDCtrlDbarIngresar
CtrlDCtrlD'foobar\n'
$ python pype.py '("%r\n" % (l,) for l in sys.stdin)'
fooCtrl-VCtrlD^DbarIngresar
CtrlDCtrlD'foo\x04bar\n'
$ 
¿Fue útil?

Solución

Ctrl-D se reconoce no necesariamente como EOF, sino como "corriente terminal read() llamar".

Si tiene una línea vacía (o simplemente presionó Ctrl-D) y presione Ctrl-D, su read() termina inmediatamente y devuelve 0 bytes leídos.Y esta es una señal de EOF.

Si tienes datos en una línea y presionas Ctrl-D, su read() termina con lo que se haya escrito, por supuesto sin una nueva línea final ('\n').

Entonces, si tienes datos de entrada, presionas Ctrl-D dos veces en una línea no vacía o una vez en una vacía, es decircon Ingresar antes.

Todo esto es válido para la interfaz normal del sistema operativo, accesible desde Python a través de os.read().

Los objetos de archivos de Python, y también los iteradores de archivos, tratan el primer EOF reconocido como terminación del archivo actual. read() llaman porque suponen que ya no hay nada.un próximo read() la llamada intenta de nuevo y necesita otra Ctrl-D para devolver realmente 0 bytes.La razón es que un objeto de archivo read() siempre intenta devolver tantos bytes como se solicite e intenta llenarlos si un sistema operativo read() devuelve menos de lo solicitado.

Como opuesto a file.readline(), iter(file) utiliza el interno read() funciones para leer y por lo tanto siempre tiene este requisito especial de la extra Ctrl-D.

yo siempre uso iter(file.readline, '') para leer líneas desde un archivo.

Otros consejos

Ctrl + D es reconocido por el dispositivo terminal, el terminal responde generando un final de archivo.Quizás esto ayude, de Wikipedia (el énfasis es mío):

En UNIX y AmigaDOS, la traducción de la pulsación de tecla a EOF la realiza el controlador de terminal, por lo que un programa no necesita distinguir los terminales de otros archivos de entrada.De forma predeterminada, el controlador convierte un carácter Control-D al comienzo de una línea en un indicador de fin de archivo.Para insertar un carácter Control-D (ASCII 04) real en el flujo de entrada, el usuario lo precede con un carácter de comando "comillas" (normalmente Control-V, aunque en algunos sistemas se logra este efecto escribiendo Control-Ddos veces ).

No puedo decir exactamente por qué el CTRL + D adicional (aunque la otra respuesta hace un muy buen trabajo), pero esto hará que la entrada se imprima después de solo un CTRL + D , pero aún necesita CTRL + D una segunda vez para salir del script

#!/usr/bin/python
DEFAULT_MODULES = ['os', 're', 'sys']

_g = {}
for m in DEFAULT_MODULES:
    _g[m] = __import__(m)

import sys
for x in eval(sys.argv[1], _g):
    print x,

Resultado:

[ root@host ~ ]$ ./test.py '(l.upper() for l in sys.stdin)'
abc
def(ENTER, CTRL+D)
ABC
DEF
qwerty(ENTER, CTRL+D)
QWERTY
[ root@host ~ ]$

Editar:

eval está devolviendo un generador en este caso, por lo que es posible que el primer EOF (CTRL + D) finalice la lectura de sys.stdin, y el segundo detiene el generador que eval está produciendo.

Generador : función que devuelve un iterador. Parece una función normal excepto que contiene declaraciones de rendimiento para producir una serie de valores utilizables en un bucle for o que se pueden recuperar uno a la vez con la función next (). Cada rendimiento suspende temporalmente el procesamiento, recordando el estado de ejecución de la ubicación (incluidas las variables locales y las sentencias try pendientes). Cuando el generador se reanuda, continúa donde lo dejó (a diferencia de las funciones que comienzan de nuevo en cada invocación).

Referencia de la clase del generador (sección 9.10)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top