Howto:close_fds=True 的解决方法并在 Windows 上重定向 stdout/stderr

Cuk*_*c0d 3 python windows subprocess

我遇到了一个问题:使用 Python 2.7,无法使用以下命令创建子进程

subprocess.Popen([.......], close_fds=True, stdout=subprocess.PIPE, ...)
Run Code Online (Sandbox Code Playgroud)

在 Windows 上,由于限制。在我的情况下需要使用close_fds,因为我不希望子进程继承已打开的文件文件描述符。这是在库中调用的,这意味着我无法控制已经打开的文件描述符(N标志)。

这是一个已知的错误,已在Python 3.4+上修复

我的问题是:如何使用子进程而不得到

如果重定向 stdin/stdout/stderr,则 Windows 平台不支持 close_fds

回答如下

Cuk*_*c0d 5

此问题在 Python 3.7+ 上默认已修复

\n\n

这绝对是一个棘手的黑客:答案是在使用模块之前迭代已经打开的文件描述符subprocess

\n\n
def _hack_windows_subprocess():\n    """HACK: python 2.7 file descriptors.\n    This magic hack fixes https://bugs.python.org/issue19575\n    by adding HANDLE_FLAG_INHERIT to all already opened file descriptors.\n    """\n    # See https://github.com/secdev/scapy/issues/1136\n    import stat\n    from ctypes import windll, wintypes\n    from msvcrt import get_osfhandle\n\n    HANDLE_FLAG_INHERIT = 0x00000001\n\n    for fd in range(100):\n        try:\n            s = os.fstat(fd)\n        except:\n            continue\n        if stat.S_ISREG(s.st_mode):\n            handle = wintypes.HANDLE(get_osfhandle(fd))\n            mask   = wintypes.DWORD(HANDLE_FLAG_INHERIT)\n            flags  = wintypes.DWORD(0)\n            windll.kernel32.SetHandleInformation(handle, mask, flags)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是一个没有它就会崩溃的示例:

\n\n
import os, subprocess\nf = open("a.txt", "w")\nsubprocess.Popen(["cmd"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\nf.close()\nos.remove(f.name)\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

回溯(最近一次调用最后一次):

\n\n

文件“stdin”,第 1 行,模块中

\n\n

WindowsError: [Error 32] Le processus ne peut pas acc\xc3\x9ader au\n fichier car ce fichier est utilis\xc3\x9a par un autre processus: \'a.txt\'

\n
\n\n

现在修复:

\n\n
import os, subprocess\nf = open("a.txt", "w")\n_hack_windows_subprocess()\nsubprocess.Popen(["cmd"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\nf.close()\nos.remove(f.name)\n
Run Code Online (Sandbox Code Playgroud)\n\n

作品。

\n\n

希望我有帮助

\n

  • 此外,在 3.7(仍处于测试版)中,子进程使用“PROC_THREAD_ATTRIBUTE_HANDLE_LIST”来限制实际继承的可继承句柄来解决此问题。 (2认同)