如何解决检测子进程何时等待 stdin
我正在制作一个能够运行任何可执行文件的终端程序(请忽略安全问题)。我需要检测子进程何时等待用户输入(来自 stdin
)。我使用以下方法启动子进程:
process = subprocess.Popen(command,close_fds=False,shell=True,**file_descriptors)
我可以想到两种检测子进程是否在等待 stdin
的方法:
- 写一个字符然后退格并检查子进程是否已经处理了这 2 个字节。但是 here 它说“CMD 确实支持退格键”。所以我需要找到一个字符,当打印到屏幕上时,它会删除命令提示符中
stdin
缓冲区中的内容。 - 第二种方法是使用
pywin32
library 并使用WaitForInputIdle
函数,如 here 所述。我查看了subprocess
库的源代码,发现它使用pywin32
并保留对进程句柄的引用。所以我尝试了这个:
win32event.WaitForInputIdle(proc._handle,100)
但是我收到了这个错误:
(1471,'WaitForInputIdle','Unable to finish the requested operation because the specified process is not a GUI process.')
同样在 windows api 文档 here 中它说:“WaitForInputIdle 只等待一次进程变为空闲;随后的 WaitForInputIdle 调用会立即返回,无论进程是空闲还是忙碌。 ”。我认为这意味着我不能多次使用该功能来解决我的问题
编辑:
这只需要在 Windows 上运行,但稍后我可能会尝试使我的程序也可以在 Linux 上计算。此外,我正在为 stdin
/stdout
/stderr
使用管道。
为什么我需要知道孩子是否在等待标准输入:
目前,当用户按下 Enter 键时,我会将他们迄今为止写入的所有数据发送到 stdin
并禁止用户更改它。问题是当子进程正在睡眠/计算并且用户写入一些输入并希望在进程再次开始读取 stdin
之前对其进行更改。
基本上让我们来看看这个程序:
sleep(10)
input("Enter value:")
假设我输入了“abc\n”。使用 cmd 时,如果孩子还在睡觉,我可以按退格键并删除输入。目前,我的程序会在检测到“\n”并将其发送到 stdin
时将所有文本标记为只读。
解决方法
class STDINHandle:
def __init__(self,read_handle,write_handle):
self.handled_write = False
self.working = Lock()
self.write_handle = write_handle
self.read_handle = read_handle
def check_child_reading(self):
with self.working:
# Reset the flag
self.handled_write = True
# Write a character that cmd will ignore
self.write_handle.write("\r")
thread = Thread(target=self.try_read)
thread.start()
sleep(0.1)
# We need to stop the other thread by giving it data to read
if self.handled_write:
# Writing only 1 "\r" fails for some reason.
# For good measure we write 10 "\r"s
self.write_handle.write("\r"*10)
return True
return False
def try_read(self):
data = self.read_handle.read(1)
self.handled_write = False
def write(self,text):
self.write_handle.write(text)
我做了一些测试,我认为 cmd 会忽略 "\r"
字符。我找不到 cmd 将其解释为实际字符的情况(就像我执行 "\b"
时发生的情况)。发送 "\r"
字符并测试它是否留在管道中。如果它确实留在管道中,则意味着孩子尚未处理它。如果我们无法从管道中读取它,则意味着孩子已经处理了它。但是我们有一个问题——如果我们不能从 stdin
读取,我们需要停止读取,否则它会干扰下一次对 stdin
的写入。为此,我们将更多的 "\r"
写入管道。
注意:我可能需要更改 sleep(0.1)
行上的时间。
我不确定这是一个好的解决方案,但如果您有兴趣,可以尝试一下。我只是假设我们在给定 2 个输入 output
和 data
的情况下为其 TIMEOUT
执行子进程。
process = subprocess.Popen(command,close_fds=False,shell=True,**file_descriptors)
try:
output,_ = process.communicate(data,TIMEOUT)
except subprocess.TimeoutExpired:
print("Timeout expires while waiting for a child process.")
# Do whatever you want here
return None
cmd_output = output.decode()
您可以找到 TimeoutExpired here 的更多示例。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。