2009-03-30 10 views
31

Ich möchte ein Programm, eine Sache zu tun, wenn wie folgt ausgeführt:Was ist der beste Weg zu sagen, ob ein Python-Programm etwas von stdin lesen kann?

cat something | my_program.py 

und eine andere Sache tun, wenn wie diese

my_program.py 

laufen Aber wenn ich von stdin gelesen, dann wird es für den Benutzer warten Ich möchte sehen, ob es etwas zu lesen gibt, bevor ich versuche, von stdin zu lesen.

+0

Was bedeutet „sollte nicht so schwer sein, wie es scheint“ bedeuten? Würde es Ihnen etwas ausmachen, die Frage mit einer Beschreibung Ihres Ziels, irgendeinem Code, den Sie bisher versucht haben, der nicht funktioniert hat, und dem, was Sie erwartet haben, zu aktualisieren? –

+0

danke Josh ... sehr geschätzt. –

Antwort

59

Wenn Sie ermitteln möchten, ob jemand Leitungsdaten in Ihr Programm ist, oder läuft es können Sie interaktiv isatty verwenden, um festzustellen, ob stdin ein Terminal:

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

Tolle Lösung, danke! –

+0

Wenn das Skript remote ausgeführt werden kann, funktioniert dieser isatty() -Ansatz noch? Zum Beispiel 'ssh somehost.com 'bash -c" python -c \ "import sys; print sys.stdin.isatty() \ "" ''gibt' False' zurück –

+0

Mit @Trey Stouts Antwort verhält sich das Skript wie erwartet über ssh. 'ssh somehost.com 'bash -c" python -c \ "import sys; Import auswählen; r, w, x = auswählen.wählen ([sys.stdin], [], [], 0); print (r) \ "" ''Druckt' [] '. Derselbe Befehl mit der Pipe ist: 'ssh somehost.com 'bash -c" echo etwas | python -c \ "import sys; Import auswählen; r, w, x = select.select ([sys.stdin], [], [], 0); print (r) \ "" ''und das druckt' [ ', mode' r 'bei 0x7ff2aad250c0>] ' –

-2

Ich kenne die Python-Befehle nicht von ganz oben, aber Sie sollten in der Lage sein, etwas mit Poll zu tun oder auswählen, um nach Daten zu suchen, die auf der Standardeingabe gelesen werden können.

Das könnte Unix OS spezifisch und anders auf Windows Python sein.

+0

Etwas wie: select.select ([sys.stdin], [], [], 0) == ([sys.stdin], [], []) Und, ja, es ist unix-spezifisch. –

2

Schlechte Nachrichten. Von einer Unix-Befehlszeilenperspektive sind diese beiden Aufrufe Ihres Programms identisch.

Unix kann sie nicht leicht unterscheiden. Was du verlangst, ist nicht wirklich vernünftig, und du musst über eine andere Art denken, dein Programm zu benutzen.

In dem Fall, wo es nicht in einer Pipeline ist, was soll es lesen, wenn es stdin nicht liest?

Soll es eine GUI starten? Wenn dies der Fall ist, möchten Sie vielleicht eine Option "-i" (--interactive) haben, um anzugeben, dass Sie eine GUI wünschen, nicht das Lesen von stdin.

Sie können Pipes manchmal von der Konsole unterscheiden, da das Konsolengerät "/ dev/tty" ist, aber das ist nicht tragbar.

+0

+1: Jeder der jemals eine Anwendung bekämpft hat, die versucht hat, süsse Tricks um diesen Willen zu umgehen schätze jeden zusätzlichen Aufwand, der ausgegeben wird, um solche süßen Tricks zu vermeiden (oder sie zumindest explizit zu machen, wie S.Lott es vorschlägt). –

+0

Diese Aufrufe sind nicht identisch, da "unknown (google)" mit sys.stdin.isatty() angegeben wurde. "isatty" ist unter Unix portierbar und wird beispielsweise in 'ls' (http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c) verwendet. Aber ja, es ist ein Trick, vor dem man sich hüten sollte. –

+0

Die Aufrufe sind identisch - nicht unterscheidbar. Die mit stdin verbundenen Geräte unterscheiden sich geringfügig. Abhängig von/dev/tty ist praktikabel, aber eine Option ist trivial und offensichtlich. –

7

Sie wollen das Select-Modul (man select auf Unix) Es wird Ihnen erlauben zu testen, ob etwas auf stdin lesbar ist. Beachten Sie, dass Select bei Windows mit Dateiobjekten nicht funktioniert. Aber aus dem Rohr beladene Frage, die ich nehme an, Sie auf einem UNIX-basierten Betriebssystem sind :)

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

Dies sagt Ihnen nicht, ob Eingabe eine Pipe ist, nur wenn Eingabe verfügbar ist. Betrachte: (Schlaf 1 && echo "foo") | ./stdin_test.py Auf meinem Rechner meldet dies "keine Pipe". –

+1

Interessante Notiz. Ich denke, das liegt nur daran, dass die Auswahl nicht blockiert. Wenn ich die 0 zu einer 5 ändere, zeigt Ihr Beispiel die geöffnete Datei richtig an. Es sollte wirklich in eine Schleife gebracht werden, die dann zyklisch sein könnte, bis Daten verfügbar waren. Guter Punkt :) –

Verwandte Themen