Что эквивалентно программе unbuffer для Windows?

Привет, в соответствии с этот пост, unbuffer подключается к команде через псевдотерминал (pty), что заставляет систему рассматривать ее как интерактивный процесс, поэтому не использует никакой буферизации stdout.

Я хотел бы использовать эту функцию в Windows. Могу ли я узнать, что эквивалентно программе unbuffer для Windows? Спасибо.

Ответ 1

Поведение, которое вы описываете, типично для приложений, использующих библиотеки времени выполнения для ввода-вывода. По умолчанию большинство библиотек времени выполнения проверяют, является ли дескриптор устройством символьного режима, таким как консоль, и, если это так, они не выполняют никакой буферизации. (В идеале библиотека времени выполнения будет обрабатывать канал так же, как консоль, но, похоже, что большинство этого не делает.)

Я не знаю ни одного разумного способа заставить такое приложение думать, что оно пишет в консоль, когда оно фактически пишет в канал.

Приложение: семь лет спустя Windows наконец поддерживает псевдоконсоли. Если вы работаете в Windows 10 v1809 или новее, этот новый API должен решить вашу проблему.

В более старых версиях Windows, если вы знаете, какой объем данных ожидать, вы в принципе могли бы использовать функции API консоли, чтобы создать консоль для приложения, в которую нужно выполнить запись, а затем прочитать выходные данные из консоли. Но вы не можете сделать это из Java, вам нужно написать приложение на C, чтобы сделать это за вас.

Аналогично, в принципе, предположительно, должно быть возможно написать драйвер устройства, эквивалентный псевдотерминалу Unix, который действует как канал, но сообщает, что он является устройством символьного режима. Но написание драйверов устройств требует особого опыта, и они должны иметь цифровую подпись, поэтому, если не существует существующего продукта, такой подход вряд ли будет осуществим.

Ответ 2

Я провел некоторое время на этом и преуспел. Я нашел этот блог во время исследования, и решил вернуться и предоставить свое решение, чтобы спасти следующего парня некоторое время. Я отвечаю как гость ложным письмом, поэтому я не буду взаимодействовать, но никакой дополнительной информации не требуется.

18 июля 12 декабря в 19:41 Гарри Джонстон написал:

"В принципе, если вы знаете, какой объем данных ожидать, вы можете использовать API-функции консоли, чтобы создать консоль для приложения, в которую нужно записывать данные, и затем прочитать вывод из консоли. Но вы не можете сделать это из Java, вам нужно написать приложение на C, чтобы сделать это за вас. "

Дело в том, что уже есть утилита, которая делает это. Он написан для несколько иного использования, но его можно использовать для достижения желаемого результата. Его предназначение состоит в том, чтобы позволить приложению консоли Windows взаимодействовать с терминалом tty в стиле Linux. Это делается путем запуска скрытой консоли и прямого доступа к буферу консоли. Если бы вы попытались его использовать - вы бы потерпели неудачу. Мне повезло, и я обнаружил, что для этой утилиты есть недокументированные ключи, которые позволят обеспечить простой небуферизованный вывод. Без переключателей происходит сбой с ошибкой - вывод не tty - при попытке передачи по конвейеру.

Утилита называется winpty. Вы можете получить его здесь:

https://github.com/rprichard/winpty/releases

Недокументированные ключи упоминаются здесь:

https://github.com/rprichard/winpty/issues/103

Я использую версию MSYS2. Вам понадобится msys-2.0.dll для его использования.

Просто запустите:

winpty.exe -Xallow-non-tty -Xplain your_program.exe | receive_unbuffered_output.exe

-Xallow-non-tty, разрешит конвейерный вывод

-Xplain удалит добавленные управляющие коды терминала Linux (или как они там называются)

Обязательные файлы:

winpty.exe
winpty-agent.exe
winpty.dll
msys-2.0.dll

winpty-debugserver.exe - не требуется

Ответ 3

Отказ от ответственности: Мой ответ касается только исполняемых файлов, скомпилированных с использованием MSVC.

Политика буферизации кодируется внутри библиотеки времени выполнения Microsoft CRT. Вы можете узнать подробности здесь. В этой статье предлагается использовать консольные дескрипторы и управлять буферами консоли для получения небуферизованного вывода.

Однако в среде Microsoft C Runtime есть недокументированная функция для наследования файлов с некоторыми внутренними флагами непосредственно из своего родительского процесса с использованием полей lpReserved2 и cbReserved2 структуры STARTUPINFO. Вы можете найти подробности в исходном коде crt, предоставленном Microsoft Visual Studio. Или найдите что-то вроде posfhnd на GitHub.

Мы можем использовать эту недокументированную функцию, чтобы предоставить дескриптор потока и указать FOPEN | FDEV флаги дочернему процессу, чтобы обмануть процесс дочернего процесса, обрабатывая тот же путь, что и дескриптор FILE_TYPE_CHAR.

У меня есть рабочий Python3 script, чтобы продемонстрировать этот метод.