2009-03-30 14 views
31

Quiero un programa para hacer una cosa si se ejecuta la siguiente manera:¿Cuál es la mejor manera de saber si un programa de Python tiene algo que leer de stdin?

cat something | my_program.py 

y hacer otra cosa si se ejecuta como esto

my_program.py 

Pero si he leído de la entrada estándar, a continuación, se va a esperar para el usuario entrada, por lo que quiero ver si hay algo que leer antes de intentar leer de stdin.

+0

¿Qué significa "no debe ser tan difícil como parece" significa? ¿Te importaría actualizar la pregunta con una descripción de tu objetivo, cualquier código que hayas probado hasta ahora que no haya funcionado y lo que esperabas que sucediera? –

+0

gracias Josh ... muy apreciado. –

Respuesta

59

Si desea detectar si alguien trata de datos de tuberías en su programa, o correr de forma interactiva puede utilizar isatty para ver si la entrada estándar es una terminal:

$ python -c 'import sys; print sys.stdin.isatty()' 
True 
$ echo | python -c 'import sys; print sys.stdin.isatty()' 
False 
+0

¡Gran solución, gracias! –

+0

Si el script se puede ejecutar de forma remota, ¿sigue funcionando este enfoque isatty()? Por ejemplo 'ssh somehost.com 'bash -c' python -c \ 'import sys; print sys.stdin.isatty() \ "" ''devuelve' False' –

+0

Usando la respuesta de @Trey Stout, la secuencia de comandos se comporta como se esperaba en ssh. 'ssh somehost.com 'bash -c' python -c \ 'import sys; importar seleccionar; r, w, x = select.select ([sys.stdin], [], [], 0); print (r) \ "" ''Imprime' [] '. El mismo comando con pipe es: 'ssh somehost.com 'bash -c' echo something | python -c \" import sys; importar seleccionar; r, w, x = select.select ([sys.stdin], [], [], 0); print (r) \ "" ''y que imprime' [ ', modo' r 'en 0x7ff2aad250c0>] ' –

-2

No conozco las órdenes de Python, pero debería poder hacer algo con sondeo o seleccionar buscar datos listos para leer en la entrada estándar.

Puede ser un sistema operativo Unix específico y diferente en Windows Python.

+0

Algo así como: select.select ([sys.stdin], [], [], 0) == ([sys.stdin], [], []) Y, sí, es unix específico. –

2

malas noticias. Desde una perspectiva de línea de comandos de Unix, las dos invocaciones de su programa son idénticas.

Unix no puede distinguirlos fácilmente. Lo que estás pidiendo no es realmente sensato, y necesitas pensar en otra forma de usar tu programa.

En el caso de que no esté en una tubería, ¿qué se supone que debe leer si no lee stdin?

¿Se supone que debe iniciar una GUI? Si es así, es posible que desee tener una opción "-i" (interactiva) para indicar que desea una GUI, no lectura de stdin.

En ocasiones, puede distinguir las tuberías de la consola porque el dispositivo de la consola es "/ dev/tty", pero esto no es portátil.

+0

+1: Cualquiera que haya peleado alguna vez con una aplicación que haya intentado trucos para evitar esto agradecer cualquier esfuerzo extra gastado para evitar trucos tan lindos (o al menos hacerlos explícitos, como sugiere S.Lott). –

+0

Esas invocaciones no son idénticas, como "desconocido (google)" señalado mediante sys.stdin.isatty(). "isatty" es portable bajo Unix, y se usa por ejemplo en 'ls' (http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c). Pero sí, es un truco para tener cuidado con el uso. –

+0

Las invocaciones son idénticas, indistinguibles. Los dispositivos conectados a stdin son ligeramente diferentes. Dependiendo de/dev/tty es factible, pero una opción es trivial y obvia. –

7

Desea el módulo de selección (man select en Unix) Le permitirá probar si hay algo legible en stdin. Tenga en cuenta que seleccionar no funcionará en la ventana con objetos de archivo. Pero a partir de su pregunta tubería cargado Estoy asumiendo que estás en un sistema operativo basado en UNIX :)

http://docs.python.org/library/select.html

root::2832 jobs:0 [~] # cat stdin_test.py 
#!/usr/bin/env python 
import sys 
import select 

r, w, x = select.select([sys.stdin], [], [], 0) 
if r: 
    print "READABLES:", r 
else: 
    print "no pipe" 

root::2832 jobs:0 [~] # ./stdin_test.py 
no pipe 

root::2832 jobs:0 [~] # echo "foo" | ./stdin_test.py 
READABLES: [<open file '<stdin>', mode 'r' at 0xb7d79020>] 
+2

Esto no le dice si la entrada es una tubería, solo si la entrada está disponible. Considere: (sleep 1 && echo "foo") | ./stdin_test.py En mi máquina esto informa "no pipe". –

+1

Nota interesante. Creo que es solo porque el select no está bloqueando. Cuando cambio el 0 a un 5, su ejemplo muestra correctamente el archivo abierto. Realmente debería ponerse en un ciclo que luego podría ciclar hasta que los datos estuvieran disponibles. Buen punto :) –

Cuestiones relacionadas