python pty.fork-它是如何工作的

python pty.fork-它是如何工作的,python,pty,Python,Pty,说- pty.fork() 叉将孩子的控制终端连接到伪终端。返回值为(pid,fd)。请注意,子项获取pid 0,并且fd无效。父对象的返回值是子对象的pid,而fd是连接到子对象的控制终端(以及子对象的标准输入和输出)的文件描述符 这是什么意思?每个进程有3个fd(标准输入、标准输出、标准输出)。 这会影响这些FD吗?子进程将不会有任何这些FD吗?我很困惑。--完全是这样。“fd是一个连接到子进程控制终端的文件描述符”->子进程将看不到任何差异,它将能够正常访问stdin/out(我不知道st

说-

pty.fork() 叉将孩子的控制终端连接到伪终端。返回值为(pid,fd)。请注意,子项获取pid 0,并且fd无效。父对象的返回值是子对象的pid,而fd是连接到子对象的控制终端(以及子对象的标准输入和输出)的文件描述符

这是什么意思?每个进程有3个fd(标准输入、标准输出、标准输出)。
这会影响这些FD吗?子进程将不会有任何这些FD吗?我很困惑。--完全是这样。

“fd是一个连接到子进程控制终端的文件描述符”->子进程将看不到任何差异,它将能够正常访问stdin/out(我不知道stderr)。唯一的区别是,“管道”的另一端不是用户正在读取/键入的终端,而是可以通过返回的fd访问的父进程。

谢谢Joni。以下是我的理解。当调用pty.fork()时。父进程连接到ptmx主进程。父级将等待键盘的输入或主机的数据

子对象关闭其stdin、stdout和stderr。并复制从机stdin、stdout.stderr。 现在,child执行了一个程序(比如bc)。当您键入1+1时,程序正在等待输入——它通过child/slave传递给master(记住child和slave都有一些stdin、stdout、stderr)。 master计算其答案“2”并写入stdout-因为父级正在等待master的数据-它拾取“2”并写入stdout


我在检查了伪终端上的几个好的旧c程序后得出了这个结论:)我不认为python的逻辑与它们没有什么不同。HTH某人。

我想我终于得到了Python中
pty.fork
的一个最简单的例子——因为我发现很难找到一个类似的例子,所以我把它贴在这里作为@joni答案的说明。其基本依据是:

  • (“自2.0以来,主\u open()和从\u open已被弃用”)
尤其令人讨厌的是,一些文档仍然引用了过时的
master\u open()
;而且
pty.fork
不会产生子进程,除非父进程从中读取文件描述符(由fork方法返回)!(请注意,在
os.fork
中没有这样的要求)另外,
os.fork
似乎更易于移植(阅读一些注释,注意
pty.fork
在某些平台上不起作用)

无论如何,这里有第一个脚本(
pyecho.py
)作为可执行文件(它只是从标准输入中读取行,然后用大写字母写回):

。。。然后,这里是实际的脚本(需要pyecho.py在同一目录中):

好吧,希望这对某人有所帮助,

干杯

使用pty.fork()的要点是,返回的伪终端(pty)文件描述符可用于以不同的方式与生成的进程通信,即通过直接写入和读取其(伪)终端,而不是stdin/out/err


还有更多信息(来自StackOverflow)和。

当使用
pty.fork()
时,子进程会被告知它正在写入一个实际的终端,一个tty,就像您通常使用的终端一样。
但是,它正在写入一个pty,一个psuedo终端,它是由另一个程序控制的tty

只有一个fd,因为子程序正在向终端写入它将要写入的内容。这是stdout、stderr和任何终端转义码的组合stdout/stderr在此上下文中没有任何意义,因为它们被打印到终端,并且当程序连接到pty时,它们无法单独访问(就像当您读取程序的输出时,您无法分辨哪个流是哪个流)。

如果需要,您仍然可以将stdout或stderr重定向到文件。这将在子级运行的代码的分叉部分完成。您可以重定向其标准流或重定向子流程的流

下面是一个基于sdaau答案的示例程序(他们的答案在Python3中不起作用)

#!/usr/bin/env python
# pyecho.py

import sys;

print "pyecho starting..."

while True:
  print sys.stdin.readline().upper()
#!/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()
#!/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()