Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

python - "OSError: [Errno 22] Invalid argument" on Windows with print() and output piped

I've come across some (to me) weird behaviour when piping the output of a Python script into wc with invalid arguments.

λ python test.py
Hello!
λ python test.py | wc -li
wc: unknown option -- i
Try 'wc --help' for more information.
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='cp1252'>
OSError: [Errno 22] Invalid argument

What is happening here?

My configuration is

  • Windows 10
  • Cmder
  • msysgit 2.5.1.windows.1
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

As @AChampion noted, this is the Windows version of IOError: [Errno 32] Broken pipe when piping: `prog.py | othercmd` with the added caveat that Python fails to raise the correct exception (i.e. BrokenPipeError).

There's issue 35754 "[Windows] I/O on a broken pipe may raise an EINVAL OSError instead of BrokenPipeError" Python's bug tracker.

Until it's fixed, I don't see a general way to handle it.

How to duplicate sys.stdout to a log file? helps solve this for Python-based output (printing via 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)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...