如何终止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
相关产品推荐
相关产品推荐

