python pty.fork - how does it work
pty, python
Solution
I think I finally got a minimal example for `pty.fork` in Python - and since I found it extremely difficult to find a similar example, I'm posting it here as an illustration of @joni's answer. It is essentially based on:
- pty - Python os.forkpty why can't I make it work - Stack Overflow
- Weird platform dependent error: Using pty.fork()
- CodeIdol - Thinking about Programming Python, 3rd Edition - Parallel System Tools - Pipes
- Python code coverage: Lib/test/test_pty.py
- [Patches] [ python-Patches-656590 ] /dev/ptmx support for ptys (cygwin) ("master_open() and slave_open have been deprecated since 2.0")
Particularly nasty bits are finding documentation that still refers to `master_open()` which is obsolete; and the fact that `pty.fork` will not spawn a child process, unless the file descriptor (returned by the fork method) is read from by the parent process! (note that in `os.fork` there is no such requirement) Also, it seems that `os.fork` is a bit more portable (read a few comments noting that `pty.fork` doesn't work on some platforms).
Anyways, here's first a script (`pyecho.py`) that acts as an executable (it simply reads lines from standard input, and writes them back in uppercase):
#!/usr/bin/env python
# pyecho.py
import sys;
print "pyecho starting..."
while True:
print sys.stdin.readline().upper()
... and then, here is the actual script (it will require that pyecho.py is in the same directory):
#!/usr/bin/env python
import sys
import os
import time
import pty
def my_pty_fork():
# fork this script
try:
( child_pid, fd ) = pty.fork() # OK
#~ child_pid, fd = os.forkpty() # OK
except OSError as e:
print str(e)
#~ print "%d - %d" % (fd, child_pid)
# NOTE - unlike OS fork; in pty fork we MUST use the fd variable
# somewhere (i.e. in parent process; it does not exist for child)
# ... actually, we must READ from fd in parent process...
# if we don't - child process will never be spawned!
if child_pid == 0:
print "In Child Process: PID# %s" % os.getpid()
# note: fd for child is invalid (-1) for pty fork!
#~ print "%d - %d" % (fd, child_pid)
# the os.exec replaces the child process
sys.stdout.flush()
try:
#Note: "the first of these arguments is passed to the new program as its own name"
# so:: "python": actual executable; "ThePythonProgram": name of executable in process list (`ps axf`); "pyecho.py": first argument to executable..
os.execlp("python","ThePythonProgram","pyecho.py")
except:
print "Cannot spawn execlp..."
else:
print "In Parent Process: PID# %s" % os.getpid()
# MUST read from fd; else no spawn of child!
print os.read(fd, 100) # in fact, this line prints out the "In Child Process..." sentence above!
os.write(fd,"message one\n")
print os.read(fd, 100) # message one
time.sleep(2)
os.write(fd,"message two\n")
print os.read(fd, 10000) # pyecho starting...\n MESSAGE ONE
time.sleep(2)
print os.read(fd, 10000) # message two \n MESSAGE TWO
# uncomment to lock (can exit with Ctrl-C)
#~ while True:
#~ print os.read(fd, 10000)
if __name__ == "__main__":
my_pty_fork()
Well, hope this helps someone, Cheers!
Problem
http://docs.python.org/library/pty.html says - pty.fork()¶ Fork. Connect the child’s controlling terminal to a pseudo-terminal. Return value is (pid, fd). Note that the child gets pid 0, and the fd is invalid. The parent’s return value is the pid of the child, and fd is a file descriptor connected to the child’s controlling terminal (and also to the child’s standard input and output). What's does this mean ? Every process has 3 fd (stdin,stdout,stderr). Does this affects these fds now ? will child process won't have any of these fds? I'm confused.--totally.