如何通过Python在shell脚本弹出的独立终端中执行make dtbs命令
你之前单独调用subprocess.call("make dtbs", shell=True)没法生效,核心原因是这个调用会新开一个完全独立的shell进程,和执行xxx.sh时弹出的终端进程没有任何输入输出管道关联,两个完全隔离的程序,自然没法把命令传到弹出的窗口里。
以下是按稳定性优先级排序的可行方案:
方案1:预置全链路执行命令,彻底去掉交互环节(最高优先级)
绝大多数场景下弹出独立终端,本质是你的xxx.sh脚本内部本身带了拉起独立终端的逻辑(比如Linux下调用gnome-terminal/xterm、Windows下调用start命令拉起cmd),执行到等待输入的节点才会卡住。
这个方案的核心是不要等脚本自己弹终端、走到交互步骤再手动输,而是在终端启动时就把所有要执行的命令一次性传进去,根本不给需要交互的机会:
- 如果是Linux GNOME桌面环境,把原来的调用逻辑替换为:
subprocess.call(["gnome-terminal", "--", "bash", "-c", "./xxx.sh; make dtbs; exec bash"])
末尾的exec bash作用是执行完所有命令后保留终端窗口,方便查看构建日志
- 如果是Windows cmd环境,替换为:
subprocess.call(["cmd", "/k", "./xxx.bat && make dtbs"])
/k参数同样是为了执行完命令后保留cmd窗口
这个方案没有跨进程传递输入的不确定性,命令从终端启动时就已经预置完成,成功率最高。
方案2:绑定子进程输入管道,定向注入命令
如果没法修改xxx.sh的内容、必须保留脚本自动弹终端的逻辑,可以在启动脚本时就把它的输入管道接到自己可控的对象上,等脚本走到等待输入的节点时,直接往管道里写入对应命令。
*注意:这个方案生效的前提是,脚本是从标准输入读取交互内容的,如果脚本硬编码了直接从物理tty设备(比如/dev/tty)读输入,管道注入会失效。
参考实现代码:
import subprocess import time # 启动脚本时绑定可写的标准输入管道 proc = subprocess.Popen( "./xxx.sh", shell=True, stdin=subprocess.PIPE, text=True ) # 等待脚本运行到等待手动输入的节点,时长可根据脚本实际的卡住时间调整 time.sleep(2) # 往管道写入命令,带换行符模拟人工按回车确认 proc.stdin.write("make dtbs\n") proc.stdin.flush() # 等待脚本全流程执行完成 proc.wait()
方案3:系统级窗口按键模拟(兜底方案)
如果脚本硬编码了从物理tty读输入、前两个方案都失效,可以用桌面系统的按键模拟能力,把make dtbs和回车的按键事件直接发送到弹出的终端窗口上,效果和人手动敲键盘完全一致:
- Linux环境可以搭配
xdotool工具,识别到弹出的终端窗口后,定向发送对应的按键序列 - Windows环境可以通过
pywin32找到弹出的终端窗口句柄,调用系统输入接口发送按键事件
这个方案稳定性相对较差,一旦终端窗口焦点丢失,就可能把命令输到其他程序窗口里,仅作为兜底使用。
常见踩坑提醒
- 没有管道关联的两个独立subprocess进程是完全隔离的,不要指望两个独立调用会自动共享输入输出
- 写入注入命令时一定要带末尾的换行符,否则程序会判定输入未完成,卡在等待回车的状态
- 自动化流程尽量减少依赖交互环节,能提前预置的命令尽量提前配置,降低运行时的不确定性
内容的提问来源于stack exchange,提问作者Eric Hsieh

