Windows 上使用 print() 和管道输出时出现“OSError: [Errno 22] Invalid argument”

Nik*_*s R 6 python windows msysgit wc

当将 Python 脚本的输出传递到带有无效参数的管道时,我遇到了一些(对我来说)奇怪的行为wc

\n\n
\xce\xbb python test.py\nHello!\n\xce\xbb python test.py | wc -li\nwc: unknown option -- i\nTry 'wc --help' for more information.\nException ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='cp1252'>\nOSError: [Errno 22] Invalid argument\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里发生了什么?

\n\n

我的配置是

\n\n
    \n
  • Windows 10
  • \n
  • 指挥者
  • \n
  • msysgit 2.5.1.windows.1
  • \n
\n

Nic*_*lay 3

正如@AChampion 指出的,这是 IOError 的 Windows 版本:[Errno 32] 管道传输时损坏管道:`prog.py | othercmd`附加警告,Python 无法引发正确的异常(即BrokenPipeError)。

Python 的 bug 跟踪器存在问题 35754 “损坏的管道上的 [Windows] I/O 可能会引发 EINVAL OSError 而不是 BrokenPipeError” 。

在它修复之前,我看不到处理它的通用方法。

如何将 sys.stdout 复制到日志文件?有助于解决基于 Python 的输出(通过 打印sys.stdout)的问题:

class IgnoreBrokenPipe(object):
    def __init__(self, stream):
        self.stream = stream
        def ignore_einval(fn):
            from functools import wraps
            @wraps(fn)
            def wrapper(*args, **kwargs):
                try:
                    return fn(*args, **kwargs)
                except OSError as exc:
                    if exc.errno != 22:
                        raise exc
                    else:  # mimicking the default SIGPIPE behavior on Windows
                        sys.exit(1)
            return wrapper

        self.write = ignore_einval(lambda data: self.stream.write(data))
        self.flush = ignore_einval(lambda: self.stream.flush())

import sys
sys.stdout = IgnoreBrokenPipe(sys.stdout)
Run Code Online (Sandbox Code Playgroud)