Python如何在退出时关闭自己的CMD窗口

6

我正在运行多个进程(数百个),每个进程都是使用以下命令调用的python程序:

command = 'start cmd /k call python %s' % (some_py_prog)
os.system(command)

在执行命令后,/k会保留cmd窗口以便检查错误。然而,当我调用数百个作业时,我的屏幕变得混乱。

那么如何让Python仅在成功完成时关闭其自己的主机cmd窗口?我需要看到出错的作业。


你为什么要使用一个Python脚本来启动一个运行Python脚本的shell窗口,而不是让Python脚本导入和运行其他Python脚本/函数(应该这样做)? - DeepSpace
内存管理。如果我从一个 Python 脚本中调用尽可能多的作业,顶级命名空间会增长并调用操作系统获取更多内存。这没问题,但我发现只有当整个 Python 程序完成后(即使使用 gc.collect(),操作系统仍标记该空间正在使用),才释放此内存。通过以这种方式处理事情,命名空间被分隔开来,并且为每个命名空间分配的内存在每个 Python 子程序关闭时由操作系统释放。子程序使用其他程序(由我的工作强制使用 MS 和第三方程序)- 这是我发现的管理系统内存的唯一方法。 - SteveBuk
2个回答

7
简短回答:只需使用/c而不是/k将导致cmd脚本在命令终止时立即退出,这正是您要求的。
command = 'start cmd /c call python %s' % (some_py_prog)
os.system(command)

但是你在这里堆叠了一些不必要的 cmd.exe:一个用于 os.system 调用,一个用于明确的 cmd.c。你可以简单地使用 subprocess 模块:

subprocess.call('python %s' % (some_py_prog), 
    creationflags = subprocess.CREATE_NEW_CONSOLE)

创建标志足以要求系统在新控制台中启动新进程,并在命令终止时关闭。如果需要预处理一些cmd特性(例如io重定向),可以选择添加shell=True选项。
(更多细节请参见我另一个答案中的评论,尤其是eryksun的评论)

如果您想在出现错误时保持新控制台打开,可以将其作为“'python -i%s'”运行。如果您正在使用py启动器,则还可以将-i选项添加到shebang中。 - Eryk Sun

4
让我们先分析下这两行Python脚本在执行时到底做了什么。感谢eryksun进行了深入的研究,得出了正确的描述,如下所示: os.system()会导致在前台执行cmd.exe /C,并生成一个控制台窗口,直到Windows命令解释器终止才会继续执行Python脚本。如果Python脚本本身在控制台中执行,则启动的cmd.exe会继承该控制台。
此命令进程以start开始,它是cmd.exe的内部命令,生成一个带有前景控制台窗口的命令进程。没错,但是这第二个命令进程在执行命令后立即终止。如果您想查看由执行脚本或Python解释器本身产生的错误输出,则不太好。
因此,第二个命令进程会使用选项/k启动cmd.exe,以保持运行,继承由start创建的控制台和在完成指定命令的执行后打开的控制台窗口。
第二个命令进程运行内部命令call,这根本不必要,因为python实际上是python.exe,是一个控制台应用程序,而不是批处理文件。因此,根本不需要使用call
建议始终使用完整的文件名指定应用程序和脚本,即文件名+文件扩展名,而不仅仅是文件名。如果可执行文件/脚本的路径已知且固定,则也应该指定它。这使得应用程序/脚本的执行独立于当前目录和环境变量PATHEXTPATH
Python解释器在第二个控制台中执行指定的Python脚本。
os.system()启动的第一个命令进程在start完成后立即终止,而这已经发生在启动cmd.exe /k时,而python.exe正在解释Python脚本。
因此,剩下的是第二个命令进程运行带脚本的Python解释器。这个命令进程在Python解释器完成执行指定Python脚本后,仍将保持运行。
因此,目标是在Python解释器完成执行Python脚本并且没有出现错误时,终止第二个带有控制台窗口的命令进程。
嗯,我根本没有安装Python,但我想执行脚本时出现错误会以大于0的返回代码退出。否则,成功执行脚本时返回代码为0。
因此,可以使用以下命令:
command = 'start cmd.exe /K python.exe %s ^&^& exit' % (some_py_prog)
os.system(command)

第二个命令进程启动的执行命令行为start cmd.exe /K,现在包含两个命令:

  1. Python解释器python.exe和要执行的脚本作为参数
  2. 内部命令exit,这个第二个命令应该由Windows命令解释器执行,只有在第一个命令的退出代码是0的情况下才会执行,因为使用了运算符&&

有关单个命令行中包含多个要执行的命令的详细信息,请参见Single line with multiple commands using Windows batch file上的答案。

在此必须使用Windows命令解释器的转义字符——插入符号^来转义每个&符号。否则,&&将被第一个运行start的命令进程解释为成功执行start后要运行的附加命令。

请注意,我没有安装Python,因此仅从命令提示符窗口使用批处理文件Test.bat进行以下测试,其中包含单个命令行@echo %~dp0 executed. & exit /B 1

start cmd.exe /K call Test.bat ^&^& exit

Test.bat是批处理文件而不是可执行文件,需要使用命令call。由于Test.bat以返回代码1退出,因此没有特定窗口标题的启动命令进程仍然保持打开状态。如果我在命令行末尾将数字1修改为0,则启动的命令进程自行退出。

当脚本代码检测到错误并使用此解决方案时,当然需要脚本代码本身停止脚本执行。


谢谢 Mofi!这个方法很有用,它让我看到了那个有问题的进程在做什么/找出了要修复的漏洞。我知道16,128个作业中肯定有一个(某个地方)有问题,但只有16,023个返回... :) 感谢您,向您致敬! - SteveBuk

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