Soweit ich weiß, wenn ich Folgendes eingebe ...
python -i
... der Python-Interpreter liest jetzt aus stdin und verhält sich (offensichtlich) so:
>>> print "Hello"
Hello
Ich würde erwarten, dass es dasselbe tut, wenn ich das tue:
echo 'print "Hello"' > /proc/$(pidof python)/fd/0
Dies ist jedoch die Ausgabe (eine tatsächliche leere Zeile):
>>> print "Hello"
<empyline>
Das sieht für mich so aus, als hätte es nur das genommen print "Hello"\n
und an es geschrieben stdout
, es aber nicht interpretiert. Warum funktioniert das nicht und was müsste ich tun, damit es funktioniert?
proc
file-descriptors
Sheppy
quelle
quelle
Antworten:
Das Senden von Eingaben an Shells / Dolmetscher auf diese Weise ist sehr problemanfällig und es ist sehr schwierig, zuverlässig zu arbeiten.
Der richtige Weg ist die Verwendung von Sockets. Aus diesem Grund wurden sie erfunden. Sie können dies in der Befehlszeile tun
ncat
nc
odersocat
einen Python-Prozess an einen einfachen Socket binden. Oder schreiben Sie eine einfache Python-Anwendung, die an den Port bindet und auf Befehle wartet, die auf einem Socket interpretiert werden sollen.Sockets können lokal sein und dürfen keiner Weboberfläche ausgesetzt sein.
Das Problem ist, dass, wenn Sie
python
von der Befehlszeile aus starten , diese normalerweise an Ihre Shell angehängt wird, die an ein Terminal angeschlossen ist. Tatsächlich können wir sehenWenn Sie also in
stdin
Python schreiben, schreiben Sie tatsächlich in daspty
Pseudo-Terminal, bei dem es sich um ein Kernel-Gerät handelt, nicht um eine einfache Datei. Es verwendetioctl
nichtread
undwrite
, so dass Sie die Ausgabe auf Ihrem Bildschirm sehen, aber es wird nicht an den erzeugten Prozess gesendet (python
)Eine Möglichkeit, das, was Sie versuchen, zu replizieren, ist ein
fifo
odernamed pipe
.Sie können auch
screen
nur zur Eingabe verwendenquelle
sleep 300 > python_i.pipe &
), schließt sich die andere Seite nicht undpython
akzeptiert weiterhin Befehle im Rohr. Es gibt keine EOF als solche, die von gesendet wirdecho
.|
Rohren nicht vermeidbar , aber richtig?echo something > fifo
würde aber dazu führen, dass es einen EOF bekommt, der viele Anwendungen stoppen würde. Diesleep infinity > fifo
Problemumgehung hat meine Mitte jedoch nicht überschritten, danke!python -i <> fifo
Der Zugriff greift nicht auf den Dateideskriptor 0 der Prozess- PID zu , sondern auf die Datei, die die PID im Dateideskriptor 0 geöffnet hat. Dies ist eine subtile Unterscheidung, aber wichtig. Ein Dateideskriptor ist eine Verbindung, die ein Prozess zu einer Datei hat. Schreiben in einen Dateideskriptor schreibt in die Datei, unabhängig davon, wie die Datei geöffnet wurde.
/proc/PID/fd/0
Wenn es sich um eine reguläre Datei handelt, wird die Datei durch Schreiben geändert. Die Daten sind nicht unbedingt das, was der Prozess als Nächstes liest: Sie hängen von der Position ab, die dem Dateideskriptor zugeordnet ist, den der Prozess zum Lesen der Datei verwendet. Wenn ein Prozess geöffnet wird , erhält er dieselbe Datei wie der andere Prozess, die Dateipositionen sind jedoch unabhängig.
/proc/PID/fd/0
/proc/PID/fd/0
Wenn es sich um eine Pipe handelt, werden die Daten beim Schreiben an den Puffer der Pipe angehängt. In diesem Fall liest der Prozess, der aus der Pipe liest, die Daten.
/proc/PID/fd/0
Wenn ein Terminal ist, dann ist es das Schreiben ausgibt , um die Daten auf einem Terminal. Eine Terminaldatei ist bidirektional: Beim Schreiben werden die Daten ausgegeben, dh das Terminal zeigt den Text an. Das Lesen von einem Terminal gibt die Daten ein, dh das Terminal überträgt Benutzereingaben.
/proc/PID/fd/0
Python liest und schreibt sowohl in das Terminal. Wenn Sie ausführen
echo 'print "Hello"' > /proc/$(pidof python)/fd/0
, schreiben Sieprint "Hello"
an das Terminal. Das Terminal wirdprint "Hello"
wie angewiesen angezeigt . Der Python-Prozess sieht nichts, er wartet immer noch auf Eingaben.Wenn Sie Eingaben in den Python-Prozess einspeisen möchten, müssen Sie das Terminal dazu bringen. Siehe crasic Antwort nach Möglichkeiten , das zu tun.
quelle
Aufbauend auf den Aussagen von Gilles müssen wir die Informationen tatsächlich an das Terminal senden, wenn wir in den Standard eines Prozesses schreiben möchten, der an ein Terminal angehängt ist. Da ein Terminal jedoch sowohl als Eingabe- als auch als Ausgabeform dient, kann das Terminal beim Schreiben nicht erkennen, dass Sie in einen darin ausgeführten Prozess und nicht in den "Bildschirm" schreiben möchten.
Linux hat jedoch eine Nicht-Posix-Methode zum Simulieren von Benutzereingaben über eine ioctl-Anforderung namens
TIOCSTI
(Terminal-E / A-Steuerung - Simulieren von Terminaleingaben), mit der wir Zeichen an ein Terminal senden können, als ob sie von einem Benutzer eingegeben worden wären.Ich bin mir nur oberflächlich bewusst, wie das funktioniert, aber basierend auf dieser Antwort sollte es möglich sein, dies mit etwas in der Art von zu tun
Einige externe Ressourcen:
http://man7.org/linux/man-pages/man2/ioctl.2.html
http://man7.org/linux/man-pages/man2/ioctl_tty.2.html
quelle