在Windows中监视由shell命令创建的子进程

5

我使用subprocess.Popen打开一个程序:

import subprocess

prog = subprocess.Popen(['myprog', args], shell=True)

我想在我的代码继续执行之前,监视进程“myprog”并等待其终止。

我面临的问题是prog.pid是shell的PID而不是“myprog”的PID,我不知道如何获取“myprog”的PID。 我尝试使用psutil查找prog.pid的子进程:

parent = psutil.Process(prog.pid)
children = parent.children(recursive=True)

但是返回了一个空列表。

不幸的是,我无法在没有shell的情况下启动'myprog'。 当我使用shell=False运行命令时,我收到以下错误消息:FileNotFoundError: [WinError 2] 找不到指定的文件

我已经搜索了各种信息,但所有有用的结果都是为非Windows用户准备的。


你确定你不能在没有shell的情况下编写程序吗?你能解释一下为什么吗?也许可以用实际的命令行来说明。因为这是可以修复的。 - Jean-François Fabre
我正在尝试使用命令“atom path\to\file\to\open”打开Atom。 - EDWhyte
你能打出 where atom 吗?我们在这里要去某个地方。 - Jean-François Fabre
可以的。输出在C:\Users\Username\AppData\Local\atom\bin,包含2个文件atomatom.cmd - EDWhyte
1个回答

1
你的atom命令可能是一个.cmd文件,它启动了一个可执行文件,这解释了shell=True的必要性。
你不需要重新编写Python中的.bat文件,但也不需要可执行文件PID。
如果可执行文件结束,批处理文件也结束,因此忘记监视prog.pid,只需在同一Python脚本中使用poll监视progpoll方法允许检查进程是否已结束(如果已结束,则返回退出代码;如果未结束,则返回None),并且这是非阻塞的,因此您随时都可以这样做:
if prog.poll() is not None:
    # process has ended
    print("ended")

让我们回想一下阻塞等待的做法:
return_code = prog.wait()

但在你的情况下,atom.cmd 命令似乎会在后台启动进程,这样就无法在没有 PID 的情况下监视它。

在这种情况下的解决方法是复制 atom.cmd,删除 start 前缀以在前台运行可执行文件,并运行该副本。

(或者,由于 cmd 调用了另一个 atom.cmd 文件,如您所评论的那样,从 atom.cmd 原始目录中找到文件 app-1.13.0\resources\cli\atom.cmd 并在那里删除 start 前缀)


我尝试使用 prog.pollprog.wait(),但它们很快就终止了,这促使我相信我正在监视 shell 而不是 'myprog'。 - EDWhyte
我在文本编辑器中打开了atom.cmd文件,其内容如下:第1行@echo off,第2行"%~dp0\..\app-1.13.0\resources\cli\atom.cmd" %*。我没有看到start前缀。 - EDWhyte
2
虽然这并不改变问题,但是实际上,Popen 并不需要 shell=True 来运行 .cmd 或者 .bat 文件。然而,你必须使用带有扩展名的完整文件名,因为底层的 CreateProcess 调用只会尝试追加 ".EXE" 扩展名。 - Eryk Sun
@EDWhyte请看我的编辑,尝试将另一个atom.cmd文件上的start删除。 - Jean-François Fabre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接