gpt4 book ai didi

python - 如何用 `stdin=sys.stdin` 重现 `stdin=PIPE` ?

转载 作者:IT王子 更新时间:2023-10-29 00:38:55 28 4
gpt4 key购买 nike

我有以下代码可以完全按预期工作:

from subprocess import Popen

process = Popen(
["/bin/bash"],
stdin=sys.stdin,
stdout=sys.stdout,
stderr=sys.stderr,
)
process.wait()

我可以交互式地使用 bash、tab works 等。

但是,我想控制发送到 stdin 的内容,所以我希望以下内容起作用:

import os
import sys
from subprocess import Popen, PIPE
from select import select

process = Popen(
["/bin/bash"],
stdin=PIPE,
stdout=sys.stdout,
stderr=sys.stderr,
)

while True:
if process.poll() is not None:
break

r, _, _ = select([sys.stdin], [], [])

if sys.stdin in r:
stdin = os.read(sys.stdin.fileno(), 1024)
# Do w/e I want with stdin
os.write(process.stdin.fileno(), stdin)

process.wait()

但行为是不一样的。我尝试了另一种方法(通过 pty):

import os
import sys
import tty
from subprocess import Popen
from select import select

master, slave = os.openpty()
stdin = sys.stdin.fileno()

try:
tty.setraw(master)
ttyname = os.ttyname(slave)

def _preexec():
os.setsid()
open(ttyname, "r+")

process = Popen(
args=["/bin/bash"],
preexec_fn=_preexec,
stdin=slave,
stdout=sys.stdout,
stderr=sys.stderr,
close_fds=True,
)

while True:
if process.poll() is not None:
break

r, _, _ = select([sys.stdin], [], [])

if sys.stdin in r:
os.write(master, os.read(stdin, 1024))
finally:
os.close(master)
os.close(slave)

而且行为非常接近,只是制表符仍然不起作用。嗯,选项卡已正确发送,但我的终端没有显示完成,即使它是由 bash 完成的。箭头还显示 ^[[A 而不是遍历历史。

有什么想法吗?

最佳答案

我所需要的只是将我的 sys.stdout 设置为原始。我还发现了 3 件事:

  • 我需要在 sys.stdout 上恢复终端设置
  • subprocess.Popen 有一个 start_new_session 参数,它执行我的 _preexec 函数正在执行的操作。
  • select.select 接受第四个参数,这是放弃前的超时。它让我避免在退出后陷入选择循环。

最终代码:

import os
import sys
import tty
import termios
import select
import subprocess

master, slave = os.openpty()
stdin = sys.stdin.fileno()

try:
old_settings = termios.tcgetattr(sys.stdout)
tty.setraw(sys.stdout)

process = subprocess.Popen(
args=["/bin/bash"],
stdin=slave,
stdout=sys.stdout,
stderr=sys.stderr,
close_fds=True,
start_new_session=True,
)

while True:
if process.poll() is not None:
break

r, _, _ = select.select([sys.stdin], [], [], 0.2)

if sys.stdin in r:
os.write(master, os.read(stdin, 1024))
finally:
termios.tcsetattr(sys.stdout, termios.TCSADRAIN, old_settings)
os.close(master)
os.close(slave)

关于python - 如何用 `stdin=sys.stdin` 重现 `stdin=PIPE` ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37371389/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com