You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Python脚本暂停执行直至内层subprocess完成?

问题场景

需要创建批处理文件run.bat以启动另一个批处理文件command.bat,要求Python脚本暂停执行,直到内层子进程完全运行完毕。

此前尝试的两种方法均失败:

  • 通过父进程启动时创建文件、结束时删除的方式判断进程状态,但内层进程为独立线程,该方法无效。
  • 尝试提取批处理进程ID,用tasklist检查进程是否存在,但仅能获取父subprocess的PID,无法拿到内层进程的PID,因此失败。相关代码如下:
import os
import subprocess
from datetime import datetime

def check_process_exists(pid_to_check):
    try:
        output = os.popen('tasklist').read()

        print(output)
        pids = []
        lines = output.splitlines()
        for line in lines[1:]:
            parts = line.split()
            if len(parts) >= 2:
                pid = parts[1]
                pids.append(pid)
        process_ids = [item for item in pids if item.isdigit()]
        process_ids = [int(item) for item in process_ids]
        print("process",process_ids)
        for pid in process_ids:
            if pid_to_check == pid:
                print("process found")
                return True
        print("not found")
        return False

    except subprocess.CalledProcessError:
        return False

def create_run_bat_file(self):
    """
    Create run.bat file with additional commands to create and delete a text file.
    """
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = "{}_{}".format(self.job_name, timestamp)
    text_file_path = os.path.join(os.environ["Temp"], "{}.txt".format(filename))
    # Define the run.bat file path
    run_bat_file = os.path.join(self.loc_path, "run.bat")

    # Create the run.bat file
    with open(run_bat_file, "w") as fid:
        fid.write('@echo off\n')
        fid.write('echo Process Holder > "{}"\n'.format(text_file_path))
        fid.write('start /B CMD /C "Q:/..../CPAU.exe %~dp0\\command.bat"\n')
        fid.write('ping 127.0.0.1 -n 2 > nul\n')
        fid.write('del "{}"\n'.format(text_file_path))
        fid.write('pause\n')

    return run_bat_file, text_file_path

def create_command_bat(self):
    # Create a common command.bat file
    cmd_bat_file = "%s/command.bat" % self.loc_path
    with open(cmd_bat_file, "w") as fid:
        line = "@echo off\n"
        line += 'robocopy "{}" "{}" '.format(self.src_path, self.dst_path)
        if self.op_type == "move_dir":
            line += '/MOVE /S /E'
        elif self.op_type == "copy_dir":
            line += '/S /E'
        elif self.op_type == "copy_file":
            line += self.file_name
        else:
            # Handle unsupported operation types here
            pass
        fid.write(line)

def execute(self):
    self.create_user_copy_dir()
    update_log_file("\n created user_copy: %s" % self.loc_path)

    # Create the single command.bat file
    self.create_command_bat() #cmd_bat_file = 

    run_bat_file, log_file_path = self.create_run_bat_file()
    # cpauprocess_pid = self.get_cpauprocess_pid()
    process = subprocess.Popen(run_bat_file,stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE, shell=True)
    # 原代码此处pid未定义,为遗漏问题
    process_not_done = check_process_exists(pid)
    while process_not_done:
        process_not_done = check_process_exists(pid)
    print("Process is finished")
可行解决方案

方案1:修改run.bat,让父进程等待内层进程完成

问题核心在于run.bat中使用了start /B CMD /C,该命令会启动独立进程,父批处理不会等待其结束。可以通过以下两种方式修改:

方式A:移除start命令,直接执行

修改create_run_bat_file方法中的批处理内容,让run.bat直接等待CPAU和command.bat执行完毕:

def create_run_bat_file(self):
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = "{}_{}".format(self.job_name, timestamp)
    text_file_path = os.path.join(os.environ["Temp"], "{}.txt".format(filename))
    run_bat_file = os.path.join(self.loc_path, "run.bat")

    with open(run_bat_file, "w") as fid:
        fid.write('@echo off\n')
        # 直接执行CPAU,run.bat会等待其完成
        fid.write('Q:/..../CPAU.exe "%~dp0\\command.bat"\n')
        fid.write('pause\n')

    return run_bat_file, text_file_path

同时修改execute方法,直接用communicate()等待父进程结束:

def execute(self):
    self.create_user_copy_dir()
    update_log_file("\n created user_copy: %s" % self.loc_path)

    self.create_command_bat()

    run_bat_file, log_file_path = self.create_run_bat_file()
    process = subprocess.Popen(run_bat_file, stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE, shell=True)
    # 等待父进程结束,此时内层进程已完成
    stdout, stderr = process.communicate()
    print("Process is finished")

方式B:使用start /WAIT强制等待

若必须保留start命令,可添加/WAIT参数让父进程等待:

start /WAIT /B CMD /C "Q:/..../CPAU.exe %~dp0\\command.bat"

方案2:直接跳过run.bat,Python直接调用CPAU

无需创建中间批处理文件,直接在Python中调用CPAU执行command.bat,可直接控制等待逻辑:

def execute(self):
    self.create_user_copy_dir()
    update_log_file("\n created user_copy: %s" % self.loc_path)

    cmd_bat_path = os.path.join(self.loc_path, "command.bat")
    self.create_command_bat()

    # 直接调用CPAU执行command.bat,等待完成
    process = subprocess.Popen(
        ["Q:/..../CPAU.exe", cmd_bat_path],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        shell=True
    )
    stdout, stderr = process.communicate()
    print("Process is finished")

方案3:获取内层进程PID(仅在必须用独立进程时使用)

若因特殊需求必须启动独立进程,可修改run.bat输出内层进程PID,Python读取后轮询等待:
修改run.bat内容:

@echo off
setlocal enabledelayedexpansion
:: 启动内层进程
start /B CMD /C "Q:/..../CPAU.exe %~dp0\\command.bat"
:: 获取刚启动的CMD进程PID
for /f "tokens=2" %%a in ('tasklist /fi "imagename eq cmd.exe" /fo list ^| findstr PID') do set inner_pid=%%a
:: 将PID写入临时文件
echo !inner_pid! > "%temp%\inner_pid.txt"
:: 轮询等待进程结束
:wait
tasklist /fi "pid eq !inner_pid!" | findstr /i "cmd.exe" >nul
if not errorlevel 1 (
    timeout /t 1 >nul
    goto wait
)
del "%temp%\inner_pid.txt"
pause

Python中读取临时文件的PID后进行轮询(此方法可靠性低于前两种)。

内容的提问来源于stack exchange,提问作者Kartikey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 06:42:03