Etwas ausführlicher, was in Deinem obigen Bsp. passiert:
Code: Alles auswählen
Prozess am Master Pseudoterminal Prozess am slave
------- read write ----------------
| | <----------- <---- <-------- | STDOUT |
| xterm | write master(/dev/ptmx) slave(/dev/pts/1) read | Python |
| | ------------> ----> | --------> | STDIN |
------- Terminal-Processing | ----------------
|
---> Output (Display über X) |
<--- Input (Keyboard über X) |
| zweiter Python-Prozess an /dev/pts/2 <----> anderer Master
| -------------------- (zB. 2. xterm)
--- | öffnet /dev/pts/1 |
| und schreibt 'q' |
--------------------
Die Schreibaktion des zweiten Python-Prozesses landet im Master und wird dort von xterm gelesen und am Bildschirm ausgegeben. Um etwas am STDIN des Slave-Prozesses zu sehen, muss es vom Master-Prozess in Master geschrieben werden. Das passiert z.B. bei Keyboard-Input, hier schreibt xterm die Zeichen in master. Je nach Terminaleinstellung werden diese Zeichen vom Pseudoterminal nur nach slave geleitet (echo off) oder nochmal nach master gespiegelt (echo on). Das ist Teil des Terminalprocessings (termios und Konsorten), welches sicherstellt, dass der slave-Prozess eine Terminalumgebung zu sehen bekommt.
Die Auftrennung von STDIN, STDOUT ist historisch bedingt, als die Terminal Ein-/Ausgabe physisch getrennt waren. Hier gibts ein Paar Hintergrund-Infos zu TTYs -
http://www.linusakesson.net/programming/tty/index.php
Am Linux-Textterminal ist diese Trennung auch noch gut nachvollziehbar, da sind Ein-/Ausgabe noch sehr nah am Keyboard-/Displaytreiber.
Auch ermöglicht diese Auftrennung in Sende- und Empfangskanal sehr elegante Pipe-Umleitungen, ohne die Bash-Skripting ziemlich alt aussehen würde.
Zu Deinem sys.stdin.read vs os.read Problem - da müsste man mal schauen, wie sys.stdin.read implementiert ist und wie es mit dem Byteparameter umgeht. os.read(fd, n) liest 1 bis n Bytes, keinesfalls mehr, während sys.stdin.read(n) auf n bytes wartet. Wahrscheinlich konsumiert sys.stdin.read mehr Bytes vom fd (und puffert diese), wodurch der Input geleert wird. Im Falle von os.read verbleiben diese im fd und werden mit dem Umschalten des Terminals in `finally` an den Master-Prozess gespiegelt und von diesem dargestellt (die Zeichen landen dabei nicht in STDOUT).