Wie überprüfe ich, ob stdin Daten hat?

69

Wie überprüfen Sie in Python, ob sys.stdinDaten vorhanden sind oder nicht?

Ich habe festgestellt, dass os.isatty(0)nicht nur überprüft werden kann, ob stdin mit einem TTY-Gerät verbunden ist, sondern auch, ob Daten verfügbar sind.

Aber wenn jemand Code wie verwendet

sys.stdin = cStringIO.StringIO("ddd")

und nach dieser Verwendung os.isatty(0)wird immer noch True zurückgegeben. Was muss ich tun, um zu überprüfen, ob stdin Daten hat?

mlzboy
quelle
3
Was genau wollen Sie erreichen?
Shahjapan
Dies geschieht, weil os.isatty(0)überprüft wird, ob die dem Dateideskriptor (fd) 0 zugeordnete Datei ein TTY ist. Wenn Sie die sys.stdinVariable ändern , ändern Sie nicht die mit fd0 verknüpfte Datei. fd0 zeigt immer noch auf das ursprüngliche stdin (was in Ihrem Fall ein TTY ist).
Cristian Ciupitu
2
Überprüfen Sie diese Antwort . Bezieht es sich auf Ihre Frage?
Muhammad Alkarouri
@Cristian Ciupitu, Sie haben Recht, ich benutze sys.stdin = cStringIO.String ("ddd"), um das stdin umzuleiten. Ich möchte überprüfen, ob sys.stdin Daten hat, wenn ich sys.stdin.read ( ) direkt wird es die folgende Sache blockieren und immer warten, wenn keine Eingabe gegeben wird
mlzboy
Ich sehe nicht, wie das Lesen von cStringIO.StringIO("ddd")blockieren könnte; Es sind immer Daten verfügbar, außer wenn EOF natürlich erreicht ist.
Cristian Ciupitu

Antworten:

77

Auf Unix-Systemen können Sie Folgendes tun:

import sys
import select

if select.select([sys.stdin,],[],[],0.0)[0]:
    print "Have data!"
else:
    print "No data"

Unter Windows kann das Auswahlmodul jedoch nur mit Sockets verwendet werden, sodass Sie einen alternativen Mechanismus verwenden müssen.

Rakis
quelle
Es tut mir leid, dass ich das Akzeptieren entfernen muss, da ich sys.stdin = cStringIO.StringIO ("ddd") verwende, um das stdin in eine Scheindatei umzuleiten, aber es hatte keine fileno-Methode erhöhen, wenn nicht select.select ([sys.stdin], [], [], 0.0) [0]: TypeError: Argument muss ein int sein oder eine fileno () -Methode haben.
mlzboy
2
@mlzboy: Nur "echte" Dateien, die vom Betriebssystem geöffnet werden, haben eine Dateideskriptornummer (übrigens sind auch Unix-Sockets oder Pipes Dateien). selectDer Aufruf der Auswahlfunktion des Betriebssystems kann nur mit diesen Dateien funktionieren. StringIOist eine virtuelle Datei, die nur dem Python-Interpreter bekannt ist, daher hat sie keinen Dateideskriptor und kann nicht verwendet werden select.
Cristian Ciupitu
2
@ mlzboy-Pipes haben eine begrenzte Puffergröße. Das Schreiben in eine Pipe, von der nichts gelesen wird, ist gefährlich, da es blockiert (Deadlock), wenn Sie versuchen, mehr als die Puffergröße zu schreiben.
Aryeh Leib Taurog
1
Diese Methode ist für mich fehlgeschlagen, wenn sie in einem Skript verwendet wurde, das von cron ausgeführt wurde. sys.stdin.isatty()hat aber für mich innerhalb von cron gearbeitet.
Dave
1
Funktioniert nicht in Jenkins, kehrt zurück <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>und nicht[]
GuySoft
68

Ich habe benutzt

if not sys.stdin.isatty()

Hier ist ein Beispiel:

import sys

def main():
    if not sys.stdin.isatty():
        print "not sys.stdin.isatty"
    else:
        print "is  sys.stdin.isatty"

Laufen

$ echo "asdf" | stdin.py
not sys.stdin.isatty

sys.stdin.isatty()gibt false zurück, wenn etwas drin ist stdin.

isatty(...)
    isatty() -> true or false. True if the file is connected to a tty device.
Erin
quelle
5
Vielen Dank! Das ist so viel einfacher als zu benutzen select.
Niklas R
Vielen Dank. Das löste mein: Echo 'vielleicht Pipe' | stdin.py + Maybe_args unter Linux. Funktioniert die Lösung von melancholynaturegirl unter Windows?
Alexx Roche
so scheint es ... C: \ Benutzer \ naturegirl \ Desktop> C: \ Python27 \ python.exe isatty.py ist sys.stdin.isatty C: \ Benutzer \ naturegirl \ Desktop> C: \ Benutzer \ naturegirl \ Desktop> echo "foo" | C: \ Python27 \ python.exe isatty.py nicht sys.stdin.isatty
Erin
23
Das ist keine gute Idee. Was ist, wenn stdin aus einer Datei weitergeleitet wird? isatty () sagt Ihnen, ob stdin direkt von einem Terminal hereinkommt, nicht, ob es mehr Daten gibt, die von stdin gelesen werden können
Lathan
2
Da grepin einem anderen Beitrag erwähnt wird, werde ich erwähnen, dass lessverwendet isatty. Ich bin hierher gekommen, um etwas zu tun wie less: Eingabe aus einer Datei lesen, wenn ein Dateipfad als Eingabeargument angegeben ist, andernfalls Eingabe von stdin lesen. Eine Alternative besteht darin, -als Alias ​​für stdin zu verwenden und nur das Dateiargument zu akzeptieren.
ws_e_c421
4

Abhängig vom Ziel hier:

import fileinput
for line in fileinput.input():
    do_something(line)

kann auch nützlich sein.

Gregg Lind
quelle
AFAIK, der Dateieingang hat einen Nachteil, der die Argumente auf den Dateinamen beschränkt, aber meine Argumente können ein Steuerbefehl sein,
mlzboy
Fair genug! Ich habe versucht, mit der gängigen Redewendung "etwas mit einer Reihe von Zeilen zu tun, möglicherweise von stdin" umzugehen :)
Gregg Lind
3

(Bearbeiten: Dies beantwortet eine verwandte Frage, die seitdem hier zusammengeführt wurde.)

Wie von anderen erwähnt, gibt es keine narrensichere Methode, um festzustellen, ob Daten von stdin verfügbar werden, da UNIX dies nicht zulässt (und allgemeiner, weil es das zukünftige Verhalten des Programms, mit dem stdin verbunden ist, nicht erraten kann).

Warten Sie immer auf stdin, auch wenn möglicherweise nichts vorhanden ist (das greptun usw.), oder fragen Sie den Benutzer nach einem -Argument.

n.caillou
quelle
1
Sie beantworten also eine Frage, indem Sie sich auf dieselbe Frage beziehen? WTF ??
ForceBru
@ForceBru Das ist in der Tat sehr verwirrend, haha. Es scheint, dass hier eine andere Frage zusammengeführt wurde. Ich habe bearbeitet.
n.caillou
Was wäre der Prozess - warten Sie auf stdin und lesen Sie bis zu einem EOF, dann verarbeiten Sie die Daten? Das heißt, wie machen grep et al. wissen, wann Daten verarbeitet und wann beendet werden müssen?
Matt
1
@Matt Die Upstream-Datenquelle ist für das Senden von EOF verantwortlich. zB printf "" | catoder while read l; do true; done; echo finishing(im zweiten Fall müssen Sie EOF / ^ D manuell
eingeben
ps Beachten Sie, dass wenn Sie nur zB catin die Befehlszeile eingeben , die Eingabe auf unbestimmte Zeit wartet. Im obigen Beispiel sendet printf EOF
n.caillou
0

Mit eingebauten Modulen kann dies mit folgendem Code erreicht werden, da Greg bereits die Idee hatte:

import fileinput
isStdin = True
for line in fileinput.input:
    # check if it is not stdin
    if not fileinput.isstdin():
        isStdin = False
        break
    # continue to read stdin
    print(line)
fileinput.close()


hsyn
quelle