Python子进程静默输入时处理KeyboardInterrupt后恢复输入显示
解决subprocess执行静默输入命令后Ctrl+C导致后续input无回显的问题
问题根源
当执行带read -s的shell命令时,read -s会将终端设置为无回显模式(输入内容不显示在屏幕上)。如果此时按下Ctrl+C触发KeyboardInterrupt中断子进程,shell来不及执行read -s的收尾操作(恢复终端回显状态),导致终端一直保持无回显模式,后续调用input()时输入的文本自然无法显示。
解决方案
核心是在中断后手动恢复终端的回显属性,可以通过Python标准库的termios模块实现终端I/O属性的控制。
方案一:保存并恢复终端初始状态
这种方式能确保终端完全回到执行子进程前的状态,兼容性更稳妥:
import subprocess import termios import sys # 保存当前终端的初始属性 stdin_fd = sys.stdin.fileno() original_term_attrs = termios.tcgetattr(stdin_fd) try: print("hit ctrl+c") subprocess.run("echo $(read -s)", shell=True) except KeyboardInterrupt: pass finally: # 强制恢复终端初始属性,确保回显开启 termios.tcsetattr(stdin_fd, termios.TCSADRAIN, original_term_attrs) text = input("Text typed here is visible now: ") print(text)
方案二:直接强制开启终端回显
如果仅需确保回显功能恢复,也可以直接修改终端属性开启回显:
import subprocess import termios import sys def enable_echo(): stdin_fd = sys.stdin.fileno() attrs = termios.tcgetattr(stdin_fd) attrs[3] |= termios.ECHO # 开启回显位(ECHO是终端属性中的回显标志) termios.tcsetattr(stdin_fd, termios.TCSADRAIN, attrs) try: print("hit ctrl+c") subprocess.run("echo $(read -s)", shell=True) except KeyboardInterrupt: pass finally: enable_echo() text = input("Text typed here is visible now: ") print(text)
适配subprocess.Popen场景
如果使用subprocess.Popen,同样可以套用上述逻辑,在finally块中恢复终端属性:
import subprocess import termios import sys stdin_fd = sys.stdin.fileno() original_term_attrs = termios.tcgetattr(stdin_fd) proc = subprocess.Popen("echo $(read -s)", shell=True) try: print("hit ctrl+c") proc.wait() except KeyboardInterrupt: proc.kill() finally: termios.tcsetattr(stdin_fd, termios.TCSADRAIN, original_term_attrs) text = input("Text typed here is visible now: ") print(text)
补充说明
termios.TCSADRAIN参数表示等待所有输出写入终端后再应用属性修改,避免终端状态混乱。finally块会确保无论子进程是否正常退出,终端属性都会被恢复,不会影响后续输入操作。
内容的提问来源于stack exchange,提问作者heygarrett
相关产品推荐
相关产品推荐

