Python 子进程陷入僵局 вслед于 raw_input() 函数

81 阅读2分钟

当尝试在 Python 脚本中使用 subprocess 模块与交互式 shell 脚本进行通信时,遇到一个问题。在主程序中调用 subprocess 运行交互式 shell 脚本时,子进程会正常结束,但主程序随后陷入僵局,并且会跳过紧随 subprocess 运行之后立即出现的 raw_input() 函数调用。

下面是示例代码:

import subprocess;
import os;
import sys;
import time;

# 定义常量
GP_HOST = "1.1.1.1:5432";
GP_USER = "admin";
GP_PASS = "password";

PG_HOST = "2.2.2.2:5432";
PG_USER = "admin";
PG_PASS = "password";

# 从用户收集所需信息
new_client_name = raw_input('New Client Name (Also DB Name): ');
# 确保新客户名称没有错别字
name_okay = raw_input("Is the name '"+new_client_name+"' okay? (Y/N): ");

while name_okay.upper() != "Y":
        new_client_name = raw_input('New Client Name (Also DB Name): ');
        name_okay = raw_input("Is the name '"+new_client_name+"' okay? (Y/N): ");

# 启动交互式数据库脚本,创建新的 Greenplum/PostgreSQL 数据库
clone_child = subprocess.Popen(['/path/to/scripts/startBuilder.sh'], stdin=subprocess.PIPE, shell='true');
clone_child.stdin.write("connect greenplum "+GP_HOST+" "+GP_USER+" "+GP_PASS+"\n");
clone_child.stdin.write("create "+new_client_name+"\n");
clone_child.stdin.write("disconnect\n");
clone_child.stdin.write("connect postgresql "+PG_HOST+" "+PG_USER+" "+PG_PASS+"\n");
clone_child.stdin.write("create "+new_client_name+"\n");
clone_child.stdin.write("disconnect\n");
clone_child.stdin.write("exit\n");

# 刷新标准输入,关闭子进程,等待主程序恢复
clone_child.stdin.flush();

# 请求添加客户端到 CEA 所需的客户端详细信息
auth_host = raw_input('Enter Authhost with Port: ');

client_version = raw_input('Client Version to Create: ');

clone_client = raw_input('Clone an existing client? (Y/n): ');
...

尽管尝试在刷新调用之后添加 clone_child.stdin.close();,程序仍然陷入僵局并跳过第一个 raw_input() 函数调用。

2、解决方案

为了解决这个问题,需要确保子进程在关闭之前完全退出。可以通过在子进程结束前调用 clone_child.communicate() 方法来实现。communicate() 方法会等待子进程退出,并返回子进程的标准输出和标准错误。

import subprocess;
import os;
import sys;
import time;

# 定义常量
GP_HOST = "1.1.1.1:5432";
GP_USER = "admin";
GP_PASS = "password";

PG_HOST = "2.2.2.2:5432";
PG_USER = "admin";
PG_PASS = "password";

# 从用户收集所需信息
new_client_name = raw_input('New Client Name (Also DB Name): ');
# 确保新客户名称没有错别字
name_okay = raw_input("Is the name '"+new_client_name+"' okay? (Y/N): ");

while name_okay.upper() != "Y":
        new_client_name = raw_input('New Client Name (Also DB Name): ');
        name_okay = raw_input("Is the name '"+new_client_name+"' okay? (Y/N): ");

# 启动交互式数据库脚本,创建新的 Greenplum/PostgreSQL 数据库
clone_child = subprocess.Popen(['/path/to/scripts/startBuilder.sh'], stdin=subprocess.PIPE, shell='true');
clone_child.stdin.write("connect greenplum "+GP_HOST+" "+GP_USER+" "+GP_PASS+"\n");
clone_child.stdin.write("create "+new_client_name+"\n");
clone_child.stdin.write("disconnect\n");
clone_child.stdin.write("connect postgresql "+PG_HOST+" "+PG_USER+" "+PG_PASS+"\n");
clone_child.stdin.write("create "+new_client_name+"\n");
clone_child.stdin.write("disconnect\n");
clone_child.stdin.write("exit\n");

# 等待子进程退出,并获取标准输出和标准错误
output, error = clone_child.communicate();

# 刷新标准输入,关闭子进程
clone_child.stdin.flush();

# Request the Client details needed to add the client to CEA
auth_host = raw_input('Enter Authhost with Port: ');

client_version = raw_input('Client Version to Create: ');
...

这样修改后,主程序将等待子进程完全退出,然后才能继续执行。这样就避免了子进程陷入僵局和跳过 raw_input() 函数调用的问题。