При использовании pty.fork()
дочернему процессу сообщается, что он пишет в реальный терминал, tty, точно так же, как тот, который вы обычно используете. Однако, он пишет в pty, псевдо-терминал, которыйэто tty, контролируемый другой программой.
Существует только один fd, потому что дочерняя программа записывает то, что будет в терминале.Это комбинация stdout, stderr и любых управляющих кодов терминала. stdout / stderr не имеют никакого смысла в этом контексте, так как они печатаются на терминале, и они не доступны индивидуально, когда программа подключена к pty (так же, как когда вы читаете вывод программы, вы не можете сказать,какой поток какой).
Вы все еще можете перенаправить stdout или stderr в файл, если хотите.Это будет сделано в раздвоенной части кода, выполняемой дочерним элементом.Вы можете перенаправить его стандартные потоки или перенаправить потоки подпроцесса.
Вот пример программы, основанной на ответе sdaau (их ответ не работает в Python3).
#!/usr/bin/env python3
import sys
import os
import time
import pty
import subprocess
def log(chars):
sys.stdout.write(" > " + chars + "\n")
def main():
# fork this script such that a child process writes to a pty that is
# controlled or "spied on" by the parent process
(child_pid, fd) = pty.fork()
# A new child process has been spawned and is continuing from here.
# The original parent process is also continuing from here.
# They have "forked".
if child_pid == 0:
log("This is the child process fork, pid %s" % os.getpid())
log("Child process will run a subprocess controlled by the parent process")
log("All output, including this text, will be written to a pty and handled ")
log("by the parent process.")
# redirect stdout/stderr if you want to here
subprocess.run(["bash"])
else:
log("This is the parent process fork, pid %s" % os.getpid())
log("the fd being read from, %s, is not stdout nor stderr; it is " % fd)
log("simply what the child is trying to write to its tty. ")
log("stdout/stderr are combined along with terminal escape codes.")
print()
# Read initial output of child process before "typing" anything in its pty
sys.stdout.write(os.read(fd, 1024).decode())
print()
# Run any bash commands you want. I/O to the fd is handled as if you are typing
# at a terminal.
os.write(fd, "ls\n".encode())
os.write(fd, "which git\n".encode())
# you can even test tab completions
os.write(fd, "git sta\t\t".encode())
while True:
log("parent will read 1024 bytes that the child wrote to its pty")
log("if no new output is available, parent will wait. Exit with ctrl+c.\n")
# take out decode() to see raw bytes the child wrote to its pty
sys.stdout.write(os.read(fd, 1024).decode())
time.sleep(1)
if __name__ == "__main__":
main()