【问题标题】:How to avoid console window with .pyw file containing os.system call?如何避免带有包含 os.system 调用的 .pyw 文件的控制台窗口?
【发布时间】:2010-12-18 09:58:26
【问题描述】:

如果我将代码文件保存为.pyw,则不会出现控制台窗口——这正是我想要的——但如果代码包含对os.system 的调用,我仍然会得到一个讨厌的控制台窗口。我认为这是由对os.system 的调用引起的。有没有办法从我的.pyw 脚本中执行其他文件而根本不打开控制台窗口?

【问题讨论】:

标签: python windows console windows-console pythonw


【解决方案1】:

您应该使用subprocess.Popen 类作为subprocess.STARTUPINFO 类的subprocess.STARTUPINFO 类的参数值实例传递,其中dwFlags 属性持有subprocess.STARTF_USESHOWWINDOW 标志和wShowWindow 属性持有subprocess.SW_HIDE 标志。这可以通过阅读866-868subprocess.py 源代码行来推断。在pythonw.exe 下运行时,可能还需要将subprocess.CREATE_NEW_CONSOLE 标志作为creationflags 参数的值传递,这不会打开控制台。

当您使用shell=True 时,只是碰巧以上所有设置都正确,但这并不意味着它是一个正确的解决方案。我认为这不是因为它增加了运行命令解释器和解析参数的开销。此外,您应该记住 (...) 根据文档,如果命令字符串是从外部输入构造的,(...) 强烈建议使用 shell=True子进程模块。

【讨论】:

  • 输入不是来自外部来源,我不在乎解析 shell 命令的开销,特别是如果避免它涉及您上面描述的过于复杂的解决方案。
  • 在这里使用 shell=True 不是正确的做法,正确解决方案的(所谓的)复杂性不会改变这一点。
  • 我不敢相信这不是最高投票的答案。这一切都是因为人们不会为了正确地做事而费心编写 3 行代码。 +1
  • 你也可以添加一个例子吗?
【解决方案2】:

Piotr 描述的解决方案实际上并不像听起来那么复杂。下面是一个将startupinfo 传递给check_call 调用以抑制控制台窗口的示例:

startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

subprocess.check_call(cmd, startupinfo=startupinfo)

由于方便函数callcheck_callcheck_output将它们的**kwargs转发给Popen构造函数,因此不需要直接使用Popen

【讨论】:

  • @ArtOfWarfare 这个问题是针对 Windows 的,因此它在其他操作系统上可能会失败也就不足为奇了。如果您想提供帮助,您应该说明您在 Mac OS 上遇到的确切错误。
  • 这是一项精心设计的工作(相对于需要多少代码),以便一个系统 (Windows) 的行为与其他系统相同,但在此过程中会破坏其他系统。我会选择shell=true - 它很短,很甜,并且适用于所有平台。哦,Mac 上的问题(我假设 *nix)是它在 STARTUPINFO() 未被识别时引发异常。
  • @ArtOfWarfare 1. 与shell=Truestartupinfo = subprocess.STARTUPINFO(); startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW; startupinfo.wShowWindow = _subprocess.SW_HIDE) 相比,它只有 3 条简单的附加行,所以并不详尽。 2. 它是特定于 Windows 的,因此只能在 Windows 上应用。因此,谈论破坏其他系统没有意义。
【解决方案3】:

人们有点懒惰...我会感谢 @Piotr Dobrogost@Frank S. Thomas 的回答。

我带来了在 Linux 和 Windows 上运行的这段代码:

import platform
import subprocess
startupinfo = None
if platform.system() == 'Windows':
    import _subprocess  # @bug with python 2.7 ?
    startupinfo = subprocess.STARTUPINFO()
    startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
    startupinfo.wShowWindow = _subprocess.SW_HIDE

稍后...

args = [exe, ...]
out = subprocess.check_output(args, startupinfo=startupinfo)

谢谢大家 ;)

另外:请注意以下使用“call”的代码也适用于 Python 2.7(在 Windows 上)以及上面的“startupinfo”代码:

def run_command(cmd, sin, sout):
    print "Running cmd : %s"%(" ".join(cmd) )
    return subprocess.call( cmd, stdin=sin, stdout=sout, startupinfo=startupinfo)

【讨论】:

  • 这对我来说非常有效,谢谢。我不明白为什么有人要使用 shell=True,这只是一个等待发生的错误。
【解决方案4】:

如果您想避免启动控制台窗口,可以尝试使用 subprocess 模块(subprocess.Popensubprocess.call 或其他)和参数 shell=True

【讨论】:

  • subprocess.check_call 在这种情况下可以很好地替代 os.system。
  • 请务必设置subprocess.check_call(args, shell=True),其中args 是您通常在控制台中键入的命令字符串。我不确定为什么当我希望控制台出现时需要shell=True,但这就是我的实验中发生的情况。
  • 确实; subprocess.Popen(...) 会打开一个控制台窗口,subprocess.Popen(..., shell=True) 不会打开一个控制台窗口。我的信念是,使用shell=True,它在当前进程的子系统中运行——对于pythonw,它将是“窗口”而不是“控制台”——而不是完全单独启动,其中作为控制台子系统可执行文件它将打开一个新的控制台窗口。
  • 我已经改进了答案,使其更准确、更具体地说明需要做什么。
  • shell=True 在这里不是必需的。查看我的回答和问题How do I eliminate Windows consoles from spawned processes in Python (2.7)?
【解决方案5】:

'os.popen' 似乎不会产生控制台窗口。脚本在“pythonw”下运行。不确定所有情况,但在我的情况下效果很好。

os.popen(command)

【讨论】:

    【解决方案6】:

    @firsthand 所说的类似,我在 wxPython-user 论坛上读到您“替换”当前正在运行的应用程序,即“command.com”或“CMD.exe” ", pyw.exe 或 pythonw.exe 当您使用类似以下内容时:

    os.execl(sys.executable, *([sys.executable]+sys.argv))
    

    another post

    虽然我不知道在这种情况下你会如何管理 io。

    我相信这种方法的一个好处是,如果您多次运行您的脚本,您的操作系统任务栏不会填满 CMD 图标。反之,如果您在任务栏中最小化了几个 CMD 并开始关闭它们,则无法分辨哪个 CMD 与哪个 pythonw 脚本一起使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      相关资源
      最近更新 更多