[英]Run interactive Bash in dumb terminal using Python subprocess.Popen and pty
这个问题类似于使用 popen 和专用的 TTY Python 运行交互式 Bash ,除了我想在“哑”终端( TERM=dumb
)中运行 Bash,并且不将 tty 置于原始模式。
下面的代码是我的尝试。 该代码类似于链接问题中给出的解决方案,主要区别在于它不会将 tty 置于原始模式,并设置TERM=dumb
。
import os
import pty
import select
import subprocess
import sys
master_fd, slave_fd = pty.openpty()
p = subprocess.Popen(['bash'],
stdin=slave_fd,
stdout=slave_fd,
stderr=slave_fd,
# Run in a new process group to enable bash's job control.
preexec_fn=os.setsid,
# Run bash in "dumb" terminal.
env=dict(os.environ, TERM='dumb'))
while p.poll() is None:
r, w, e = select.select([sys.stdin, master_fd], [], [])
if sys.stdin in r:
user_input = os.read(sys.stdin.fileno(), 10240)
os.write(master_fd, user_input)
elif master_fd in r:
output = os.read(master_fd, 10240)
os.write(sys.stdout.fileno(), output)
上面的代码有两个问题:
printf ''
,上面的代码将在打印下一个 bash 提示之前在下一行打印printf ''
。bash
所期望的那样。我应该如何解决这些问题?
这正是不将 tty 置于原始模式的副作用。 通常,处理 pty 的程序(如expect )会将外部 tty 置于原始模式。
您的 Python 脚本的 tty(或 pty)会回显您输入的内容,并且新的 pty 会第二次回显。 您可以在新 pty 上禁用 ECHO。 例如:
$ python3 using-pty.py bash-5.1$ echo hello echo hello hello bash-5.1$ stty -echo stty -echo bash-5.1$ echo hello # <-- no double echo any more hello bash-5.1$ exit exit
您的 Python 脚本的 tty 未处于原始模式,因此当您按ctrl-d 时, Python 不会获得文字ctrl-d 。 相反,Python 会到达 EOF 并且read()
返回一个空字符串。 因此,要使生成的外壳退出,您可以
user_input = os.read(sys.stdin.fileno(), 10240) if not user_input: # explicitly send ctrl-d to the spawned process os.write(master_fd, b'\\04') else: os.write(master_fd, user_input)
同样,Python 的 tty 不在原始模式下,所以当你按下ctrl-c 时,它不会得到文字ctrl-d 。 相反,它被杀死了。 作为一种解决方法,您可以捕获SIGINT
。
def handle_sigint(signum, stack): global master_fd # send ctrl-c os.write(master_fd, b'\\03') signal.signal(signal.SIGINT, handle_sigint)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.