如何将零字节写入子过程的stdin?

发布于 2025-01-31 12:50:44 字数 1784 浏览 4 评论 0原文

我想从Python脚本运行一个控制台程序。让我称它为孩子。 偶尔要继续处理,孩子希望读取来自stdin的0个数据。 为了简单起见,让我们假设孩子是以下python脚本:

child.py
import os
import sys
import time

stdin = sys.stdin.fileno()

def speak(message):
    print(message, flush=True, end="")

while True:
    speak("Please say nothing!")

    data = os.read(stdin, 1024)

    if data == b"":
        speak("Thank you for nothing.")
        time.sleep(5)
    else:
        speak("I won't continue unless you keep silent.")

成功工作(即看到“谢谢您”。打印。打印),您通常必须在运行它时ctrl+d一个Unix终端,而在 cmd powershell 中,Windows命中ctrl+z后跟Enter将执行技巧。

是一个尝试从python脚本内部运行孩子的尝试,我将其称为父母:

父母。
import os
import subprocess

def speak_to_child(child_stdin_r, child_stdin_w, message):
    child = subprocess.Popen(
        ["python", "child.py"],
        stdin=child_stdin_r,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )

    child_stdout_r = child.stdout.fileno()

    while True:
        data = os.read(child_stdout_r, 1024)
        print(f"child said: {data}")

        if data == b"Please say nothing!":
            os.write(child_stdin_w, message)


child_stdin_r, child_stdin_w = os.pipe()
speak_to_child(child_stdin_r, child_stdin_w, b"Not sure how to say nothing.")

这 在阅读“不确定什么都不说”之后。从它的stdin。

天真地更改消息b“不确定如何无话可说。”在空邮件中 b“” 没有摆脱问题,因为编写0 0到管道的字节不会导致接收端的0个字节读取。

现在,在UNIX上,我们可以通过用伪透明替换管道来轻松解决该

import pty

child_stdin_w, child_stdin_r = pty.openpty()
speak_to_child(child_stdin_r, child_stdin_w, b"\x04")

问题有效...但显然不是在窗户上。因此,现在我的问题是:

  1. 在Unix上,正在使用伪t,是强制读取0字节的最佳方法还是有更好的方法?
  2. 在Windows上,鉴于没有伪情绪,我该如何解决问题?

平台不可知的解决方案当然是理想的。

There's a console program I want to run from a python script. Let me call it the child.
Once in a while, to continue processing, the child expects to read 0 bytes of data from stdin.
For simplicity, let's assume the child is the following python script:

child.py
import os
import sys
import time

stdin = sys.stdin.fileno()

def speak(message):
    print(message, flush=True, end="")

while True:
    speak("Please say nothing!")

    data = os.read(stdin, 1024)

    if data == b"":
        speak("Thank you for nothing.")
        time.sleep(5)
    else:
        speak("I won't continue unless you keep silent.")

To work successfully (i.e. seeing "Thank you for nothing." printed), you must typically hit Ctrl+D when running it in a UNIX terminal, while in cmd or PowerShell under Windows hitting Ctrl+Z followed by Enter will do the trick.

Here's an attempt to run the child from inside a python script, which I shall call the parent:

parent.py
import os
import subprocess

def speak_to_child(child_stdin_r, child_stdin_w, message):
    child = subprocess.Popen(
        ["python", "child.py"],
        stdin=child_stdin_r,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )

    child_stdout_r = child.stdout.fileno()

    while True:
        data = os.read(child_stdout_r, 1024)
        print(f"child said: {data}")

        if data == b"Please say nothing!":
            os.write(child_stdin_w, message)


child_stdin_r, child_stdin_w = os.pipe()
speak_to_child(child_stdin_r, child_stdin_w, b"Not sure how to say nothing.")

This is of course an unsuccessful attempt as the child will clearly answer with "I won't continue unless you keep silent." after reading "Not sure how to say nothing." from its stdin.

Naively changing the message b"Not sure how to say nothing." in the parent to the empty message b"" doesn't get rid of the problem, since writing 0 bytes to a pipe won't cause a read of 0 bytes on the receiving end.

Now on UNIX we could easily solve the problem by replacing the pipe with a pseudoterminal and the empty message b"" with an EOT character b"\x04" like so:

import pty

child_stdin_w, child_stdin_r = pty.openpty()
speak_to_child(child_stdin_r, child_stdin_w, b"\x04")

This works ... but evidently not on Windows. So now my questions:

  1. On UNIX, is using a pseudoterminal the best way to force the read of 0 bytes or is there a better way?
  2. On Windows, given that pseudoterminals aren't available, how can I solve the problem?

A platform agnostic solution would of course be ideal.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文