OSError: [Errno 22] Недопустимый аргумент в Windows с функцией print() и конвейерным выводом

Я столкнулся с некоторым (для меня) странным поведением при передаче вывода скрипта Python в wc с недопустимыми аргументами.

λ 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

Что здесь происходит?

Моя конфигурация

  • Windows 10
  • Командир
  • msysgit 2.5.1.окна.1

person Niklas R    schedule 13.09.2015    source источник
comment
@champion Правильно, у него нет возможности. И это причина, по которой ошибка возникает в Python. Я хочу знать, что именно происходит из-за этого OSError и почему это связано с недопустимым аргументом, переданным в wc.   -  person Niklas R    schedule 14.09.2015
comment
wc завершается, когда он видит недопустимую опцию, которая закрывает канал, python продолжает писать в канал и терпит неудачу. К счастью, я получаю более разумное сообщение об ошибке для того же исключения (Mac OSX): BrokenPipeError: [Errno 32] Broken pipe.   -  person AChampion    schedule 14.09.2015
comment
Не придавайте значения EINVAL. CRT должен сопоставить тысячи кодов ошибок Win32 примерно с 40 значениями errno. Вероятно, ошибка Win32 здесь ERROR_NO_DATA, потому что канал закрывается. В принципе, я думаю, что это должно соответствовать EPIPE (сломанная труба), но по какой-то причине CRT использует значение по умолчанию EINVAL (недопустимый аргумент).   -  person Eryk Sun    schedule 14.09.2015


Ответы (1)


Как отметил @AChampion, это является версией Windows для IOError: [ Errno 32] Сломан канал при передаче: `prog.py | othercmd` с дополнительным предупреждением о том, что Python не может вызвать правильное исключение (например, BrokenPipeError).

Существует проблема 35754 [Windows] Ввод-вывод на сломанном конвейере вместо этого может вызывать EINVAL OSError BrokenPipeError средство отслеживания ошибок Python.

Пока это не будет исправлено, я не вижу общего способа справиться с этим.

Как дублировать 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)
person Nickolay    schedule 30.03.2021