2

Учитывая следующее:

C:\>perl -E " say STDOUT 111; say STDERR 222; say STDOUT 333; "
111
222
333

C:\>perl -E " say STDOUT 111; say STDERR 222; say STDOUT 333; " | cat
222
111
333

Порядок вывода не сохраняется при передаче команд из-за буферизации stdout и небуферизации stderr. Как надежно отключить буферизацию stdout, чтобы порядок был сохранен при передаче команд?

Я искал все, пытаясь найти решения, я пробовал такие скрипты, как unbuffer из expect пакета в cygwin и Linux, но это работает только внутри Cygwin (за ее пределами, на голой земле cmd.exe, порядок все еще неправильный , stderr по-прежнему приходит раньше, чем ожидалось.) То же самое с stdbuf -i0 -o0 -e0 ...

Любая помощь будет принята с благодарностью.

1 ответ1

0

Perl по умолчанию I/O слои буфер, и не использовать stdio сделать это по умолчанию, поэтому unbuffer и stdbuf (которые изменяют Буферизацию stdio по умолчанию) не работают.

Хотя Perl предоставляет свой собственный способ управления используемыми уровнями ввода / вывода: Переменная среды PERLIO . В соответствии с документами man perlrun должна быть возможность запустить set PERLIO=:unix перед запуском команды или для необработанного ввода-вывода, основанного на дескрипторе Windows, который все еще может быть экспериментальным / ошибочным , set PERLIO=:win32 . Либо следует обойти нормальное поведение буферизации, перейдя прямо к необработанным системным вызовам.

Если предположить, что сама cat не буферизована (я полагаю, что она использует необработанные операции чтения и записи без буферизации, так и должно быть), это все равно не гарантирует желаемого поведения. Perl может немедленно отправить данные в cat , но если cat удастся прочитать их и записать обратно быстрее, чем Perl сможет перейти к следующей строке и распечатать в STDERR , вы все равно сначала увидите STDERR . В локальных тестах (в Linux, но это должно быть очень похоже) с PERLIO=:unix , piping to cat , я увидел следующие результаты:

222111

333

затем:

222
111
333

затем:

111222

333

затем (дважды подряд):

111
222
333

Дело в том, что даже при буферизации вне уравнения трубопровод вводит условия гонки из-за параллелизма на уровне процесса. Единственный способ обойти это - убедиться, что оба потока идут в cat:

perl -E "say STDOUT 111; say STDERR 222; say STDOUT 333;" 2>&1 | cat

последовательно выводит:

111
222
333

потому что все данные отправляются в cat непосредственно перед выполнением следующей print . Единственный другой способ получить (в основном) надежный заказ - это спать между отпечатками (что позволяет cat выиграть гонку с помощью perl).

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .