[英]How do I reproduce `stdin=sys.stdin` with `stdin=PIPE`?
I have the following code that works exactly as intended: 我有以下代码完全按预期工作:
from subprocess import Popen
process = Popen(
["/bin/bash"],
stdin=sys.stdin,
stdout=sys.stdout,
stderr=sys.stderr,
)
process.wait()
I can interactively use bash, tab works, etc. 我可以交互式地使用bash,tab works等。
However, I want to control what I send to stdin, so I'd like the following to work: 但是,我想控制我发送到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()
But the behavior just isn't the same. 但这种行为并不相同。 I've tried another approach (going through a pty):
我尝试了另一种方法(通过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)
And the behavior is pretty close, except tab still doesn't work. 并且行为非常接近,除了tab仍然不起作用。 Well, tab is properly sent, but my terminal doesn't show the completion, even though it was done by bash.
好吧,tab已正确发送,但我的终端没有显示完成,即使它是由bash完成的。 Arrows also show
^[[A
instead of going through history. 箭头也显示
^[[A
而不是通过历史记录。
Any idea? 任何的想法?
All I needed was setting my sys.stdout
to raw. 我只需要将我的
sys.stdout
设置为raw。 I also found out 3 things: 我还发现了3件事:
sys.stdout
sys.stdout
上的终端设置 subprocess.Popen
has a start_new_session
argument that does what my _preexec
function is doing. subprocess.Popen
有start_new_session
说法,做什么我_preexec
功能正在做什么。 select.select
accepts a 4th argument, which is a timeout before giving up. select.select
接受第4个参数,这是放弃之前的超时。 It lets me avoid being stuck in the select loop after exiting. Final code: 最终代码:
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.