使用pty时子进程污染父终端

问题描述 投票:0回答:1

示例

我注意到cli应用程序ngrok的这种行为。对于此示例而言,这是特殊的,因为它会污染父流程终端。它的核心功能并不重要。

获取可执行文件:

wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
unzip ngrok-stable-linux-amd64.zip
# There is `ngrok` executable in this dir now

导致问题的代码:

# ngrok_python.py
# It's in the same dir as the ngrok executable
import pty
import subprocess
import shlex
import time
import sys

pty_master, pty_slave = pty.openpty()
ngrok_cmd = "./ngrok http 80" 
# This doesn't happen for others
# ngrok_cmd = "ls -la" 

ngrok = subprocess.Popen(shlex.split(ngrok_cmd), stdin=pty_slave, stdout=pty_slave, stderr=pty_slave)

# It also won't pollute the current terminal when redirected to DEVNULL
# ngrok = subprocess.Popen(shlex.split(ngrok_cmd), stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

print("The subprocess is attached to the pseudo terminal")
print("Its output should not be printed here")
print("Unless I decide to read from pty_master")

print("Checking a few times if the subprocess is done")

for i in range(3):
    time.sleep(1)
    if ngrok.poll is not None:
        print("Subprocess finished")
        sys.exit()

print("Don't want to wait any longer.")
# Running the command
python3 ngrok_python.py

预期的行为

  • 唯一的输出将来自打印语句
  • subprocess具有自定义stdout/err/in。无法访问主终端
  • 由于pty,如果我想读取子流程中发生的事情,我将从pty_master中读取它

实际行为

  • 子过程./ngrok http 80的输出使用了终端

奇怪的是,运行注释掉的部分(ngrok_cmd = "ls -la"subprocess with subprocess.DEVNULL)会导致预期的行为。

问题

  1. 如果为孩子提供的stdout/err/in已更改,为什么子进程知道如何访问父终端?
  2. 如何在python中克服这个问题?
python-3.x linux subprocess pty
1个回答
0
投票
/dev/tty设备是指进程的“控制终端”,这是进程从其父级继承的事物之一。重新分配孩子的stdinstdoutstderr不会影响其控制终端。因此,在这种情况下,子级保留与父级相同的控制终端,并且当子级打开并写入/dev/tty时,输出将直接进入父级的屏幕,而不经过子级的stdoutstderr或您的伪-终端。

要实现所需的功能,您需要将孩子与父母的控制终端离婚,并将伪终端的从属端建立为孩子的控制终端。这涉及到对setsid和/或setpgrp的调用,一些文件描述符的杂耍以及可能的其他回转,但是如果您在C中工作,则所有这些工作都由login_tty处理。

好消息是,Python pty模块中有一个方法可以为您完成所有这些操作。该方法为pty.spawn。它在Python 2和3中可用。我已经链接到Python 3文档,因为它的功能要好得多,并且包含示例程序。 pty.spawn基本上表现为pty.spawnforkexecopenpty的组合。

如果您重做程序以使用login_tty启动pty.spawn,那么我很确定您会得到想要的行为。

© www.soinside.com 2019 - 2024. All rights reserved.