Frage

Diese Frage hat hier bereits eine Antwort:

  • Warum muss ich zum Schließen zweimal Strg + D drücken? stdin? 5 Antworten

    Zu meiner eigenen Unterhaltung habe ich ein Python-Skript erstellt, mit dem ich Python für Bash-Einzeiler verwenden kann. Geben Sie einen Python-Generator-Ausdruck an. und das Skript iteriert darüber. Hier ist das Skript:

    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))
    

    Und so können Sie es verwenden.

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

    Für den beabsichtigten Gebrauch funktioniert es perfekt!

    Aber wenn ich es nicht mit Pipe füttere und es einfach direkt aufrufe, zum Beispiel: [Hervorhebung hinzugefügt, um zu zeigen, was ich tippe]

    $ python pype.py '("%r\n" % (l,) for l in sys.stdin)'
    fooEnter
    barEnter
    bazEnter
    Ctrl DCtrl D'foo\n'
    'bar\n'
    'baz\n'
    $ 
    

    Um keine Eingaben mehr zu akzeptieren und keine Ausgaben mehr zu erzeugen, muss ich entweder Enter - Strg D - Strg D oder Strg D - Strg D - Strg D . Dies verstößt gegen meine Erwartungen, dass jede Zeile wie eingegeben verarbeitet werden sollte und dass die Eingabe von Strg D das Skript jederzeit beendet. Wo ist die Lücke in meinem Verständnis?

    BEARBEITEN: Ich habe das interaktive Beispiel aktualisiert, um zu zeigen, dass ich das Zitat, das wim in seiner Antwort beschreibt, und einige weitere Beispiele nicht sehe.

    $ python pype.py '("%r\n" % (l,) for l in sys.stdin)'
    fooCtrl DCtrl DbarEnter
    Ctrl DCtrl D'foobar\n'
    $ python pype.py '("%r\n" % (l,) for l in sys.stdin)'
    fooCtrl VCtrl D^DbarEnter
    Ctrl DCtrl D'foo\x04bar\n'
    $ 
    

War es hilfreich?

Lösung

Strg-D wird nicht unbedingt als EOF erkannt, sondern als "Aktuellen read()-Aufruf beenden".

Wenn Sie eine leere Zeile haben (oder nur Strg-D gedrückt haben) und Strg-D drücken, wird Ihr read() sofort beendet und gibt 0 gelesene Bytes zurück. Und dies ist ein Zeichen für EOF.

Wenn Sie Daten in einer Zeile haben und Strg-D drücken, endet Ihr read() mit dem, was dort eingegeben wurde, natürlich ohne abschließende neue Zeile ('\n').

Wenn Sie also Eingabedaten haben, drücken Sie Strg-D zweimal einer nicht leeren Zeile oder einmal in einer leeren Zeile, dh mit Eingabe vor.

Dies gilt alles für die normale Betriebssystemschnittstelle, auf die von Python über os.read() zugegriffen werden kann.

Python-Dateiobjekte und auch Dateiiteratoren behandeln den ersten EOF, der als Beendigung für den aktuellen read()-Aufruf erkannt wird, da davon ausgegangen wird, dass nichts mehr vorhanden ist. Ein nächster read()-Aufruf versucht es erneut und benötigt eine weitere Strg-D , um wirklich 0 Bytes zurückzugeben. Der Grund dafür ist, dass ein read() eines Dateiobjekts immer versucht, so viele Bytes wie angefordert zurückzugeben und zu füllen, wenn ein read() eines Betriebssystems weniger als angefordert zurückgibt.

Im Gegensatz zu file.readline() verwendet iter(file) die internen read()-Funktionen zum Lesen und hat daher immer diese spezielle Anforderung des zusätzlichen Strg-D .

Ich verwende immer iter(file.readline, ''), um zeilenweise aus einer Datei zu lesen.

Andere Tipps

Strg + D wird vom Endgerät erkannt, das Terminal reagiert darauf, indem es ein Dateiende generiert.Vielleicht hilft dies aus Wikipedia (Schwerpunkt Mine):

Unter UNIX und AmigaDOS wird die Übersetzung des Tastenanschlags in EOF vom Terminaltreiber ausgeführt, sodass ein Programm Terminals nicht von anderen Eingabedateien unterscheiden muss.Standardmäßig konvertiert der Treiber ein Control-D-Zeichen am Zeilenanfang in einen Dateiende-Indikator.Um ein tatsächliches Control-D-Zeichen (ASCII 04) in den Eingabestream einzufügen, muss dem Benutzer ein "Anführungszeichen" -Befehl vorangestellt werden (normalerweise Control-V, obwohl Sie auf einigen Systemen diesen Effekt durch Eingabe von Control-D erzielenzweimal ).

Ich kann nicht genau sagen, warum die zusätzliche STRG + D-Taste (die andere Antwort macht das allerdings sehr gut), aber dadurch wird die Eingabe nur nach einer einzigen STRG + D , aber Sie müssen noch ein zweites Mal STRG + D drücken, um das Skript zu beenden

#!/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,

Ausgabe:

[ 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 ~ ]$

Bearbeiten:

eval gibt in diesem Fall einen Generator zurück. Daher beendet möglicherweise der erste EOF (STRG + D) das Lesen von sys.stdin und der zweite stoppt den Generator, den eval erzeugt.

Generator - Eine Funktion, die einen Iterator zurückgibt. Es sieht aus wie eine normale Funktion, außer dass es Yield-Anweisungen zum Erzeugen einer Reihe von Werten enthält, die in einer for-Schleife verwendet werden können oder die einzeln mit der next () -Funktion abgerufen werden können. Jeder Ertrag setzt die Verarbeitung vorübergehend aus und speichert den Status der Standortausführung (einschließlich lokaler Variablen und ausstehender try-Anweisungen). Wenn der Generator fortgesetzt wird, wird er dort fortgesetzt, wo er aufgehört hat (im Gegensatz zu Funktionen, die bei jedem Aufruf neu gestartet werden).

Referenz zur Generatorklasse (Abschnitt 9.10)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top