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

如何终止Python subprocess启动的外部应用程序?求跨平台解决方案

跨平台关闭通过subprocess打开的PDF查看器

问题场景

在macOS上使用以下代码通过系统默认应用Preview打开PDF文件:

import subprocess
doc = subprocess.Popen(['open', 'path_to_doc.pdf'])

尝试终止Preview时遇到以下问题:

  • doc.pid对应的open进程很快变为僵尸状态,无法通过它关联到实际的Preview进程;
  • 依赖doc.pid+1杀死Preview的方法不具备通用性;
  • macOS专属的osascript命令可以关闭Preview,但无法跨平台使用。

问题原因

macOS的open命令仅负责启动目标应用,启动完成后立即退出,因此它的PID对应的进程会快速变成僵尸,且实际的Preview进程与open进程没有父子进程关联,导致psutil无法通过open进程找到子进程。

跨平台解决方案

方案1:直接启动PDF阅读器进程(推荐)

跳过系统的open/start/xdg-open等中间命令,直接启动目标PDF阅读器的可执行文件,这样能直接拿到应用进程的PID,方便后续精准管理。

import subprocess
import sys
import psutil

def open_pdf(pdf_path):
    """跨平台打开PDF,返回对应的进程对象"""
    if sys.platform == 'darwin':
        # macOS:直接启动Preview
        return subprocess.Popen(['/Applications/Preview.app/Contents/MacOS/Preview', pdf_path])
    elif sys.platform == 'win32':
        # Windows:示例启动Edge(可替换为用户默认阅读器,如AcroRd32.exe)
        return subprocess.Popen(['msedge', pdf_path])
    elif sys.platform.startswith('linux'):
        # Linux:示例启动Evince(默认PDF阅读器)
        return subprocess.Popen(['evince', pdf_path])

def close_pdf_process(proc):
    """跨平台关闭PDF进程(含子进程)"""
    try:
        # 先尝试优雅终止
        proc.terminate()
        proc.wait(timeout=5)
    except subprocess.TimeoutExpired:
        # 超时则强制杀死
        proc.kill()
    # 清理所有子进程
    try:
        parent_proc = psutil.Process(proc.pid)
        for child in parent_proc.children(recursive=True):
            try:
                child.terminate()
                child.wait(timeout=2)
            except:
                child.kill()
    except psutil.NoSuchProcess:
        pass

# 使用示例
pdf_process = open_pdf('path_to_doc.pdf')
# 后续需要关闭时调用
close_pdf_process(pdf_process)

方案2:分平台关闭默认PDF阅读器

如果必须依赖系统默认应用打开PDF,可针对不同平台调用专属命令关闭默认阅读器(注意:此方法会关闭该应用的所有窗口):

import subprocess
import sys

def close_default_pdf_viewer():
    """跨平台关闭默认PDF阅读器"""
    if sys.platform == 'darwin':
        # macOS:关闭Preview
        subprocess.run(['osascript', '-e', 'quit app "Preview"'], check=False)
    elif sys.platform == 'win32':
        # Windows:关闭Edge(可替换为默认阅读器进程名,如AcroRd32.exe)
        subprocess.run(['taskkill', '/IM', 'msedge.exe', '/F'], check=False)
    elif sys.platform.startswith('linux'):
        # Linux:关闭Evince
        subprocess.run(['pkill', 'evince'], check=False)

注意事项

  • 方案1的优势是可以精准关闭当前打开的PDF对应的进程,不会影响用户其他同应用窗口;
  • 方案2需根据用户的默认PDF阅读器调整进程名,可通过系统API获取默认应用路径后再启动/关闭,进一步提升通用性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 05:35:22