2014-02-05 5 views
3

Учитывая труба в ОС Windows cmd.exe командной оболочки:Трубопровод в Windows cmd.exe не передает стандартный вывод до завершения процесса?

C:\>feed | filter 

Стандартный вывод из процесса подачи кажется, не достигнет стандартного ввода процесса фильтрации до тех пор, после завершения процесса подачи выполняется до завершения.

Этот тип «буферизации» может вызвать раздражающие задержки в выходных сообщениях для длительных процессов подачи (где вы можете нажать «ctrl-c», чтобы прервать его при раннем сбое).

Есть ли способ избежать этого, чтобы стандартный выход из процесса подачи достигнет стандартного ввода в процессе фильтрации, как только данные будут доступны? (Без буферизации)

Например, следующий упрощенный пример:

feed.bat:

@echo off 
echo something 
sleep 3 
echo something else 

filter.bat:

@echo off 
for /F "tokens=*" %%a in ('more') do (
    echo _%%a 
) 

Приведенная ниже команда ничего не отображать до истечения 3 секунд (при завершении сна):

C:\>feed | filter 
_something 
_something else 

Желаемое поведение будет заключаться в том, что печатается «_something», за которым следует 3-секундная задержка, а затем «_something else» печатается.

+0

В какой версии Windows есть команда SLEEP? Я использую TIMEOUT (или PING hack) – dbenham

+0

Это не имеет ничего общего с тем, как работает командный процессор, и все, что связано с самой программой. Который автоматически переключает вывод в буферный режим, делает трубопровод намного более эффективным. Основными функциями CRT являются _isatty() и setvbuf(). Но с новым поведением этот вывод не покидает буфер до тех пор, пока он не заполнит емкость. Или сама программа очищает буфер. Что не хватает в этой программе. Это очень удобно, если у вас есть источник программы. –

ответ

4

Трубы асинхронные в Windows cmd.exe. Они не дожидаются завершения левой части перед передачей информации вправо. Но ваша программа не демонстрирует это по двум причинам.

1) Команда FOR/F не начинает повторять любые строки до тех пор, пока команда в предложении IN() не завершится. Это справедливо для всех вариантов FOR/F. Весь результат предложения IN() буферизуется до повторения любых строк.

Так что ваш filter.bat не может продемонстрировать асинхронный характер труб.

2) Команда MORE не будет писать частичные строки - она ​​ждет, пока не получит символ новой строки перед печатью на стандартный вывод. (если он не достигнет конца файла).

Если вы хотите по-настоящему увидеть асинхронный характер труб, лучше использовать программу, которая считывает каждый символ из stdin и сразу же записывает его обратно в stdout.


Настоящая версия FEED.BAT - это несколько строк с несколькими паузами. Он также записывает три символа без перевода строки с паузой после каждого из них.

@echo off 
echo something 
timeout /nobreak 3 >nul 
echo something else 
timeout /nobreak 3 >nul 
for /l %%N in (1 1 3) do (
    <nul set /p "=%%N" 
    timeout /nobreak 3 >nul 
) 
echo(
echo Done 

Вот моя версия FILTER.JS - она ​​читает один символ из стандартного ввода и записывает их на стандартный вывод до тех пор, пока не достигнет конца файла.

while (!WScript.StdIn.AtEndOfStream) WScript.Stdout.Write(WScript.StdIn.Read(1)); 

А вот команда протестировать поведение

feed | cscript //nologo filter.js 

А вот выход с <pause> вставляется всякий раз, когда есть пауза перед тем большей производительности.

something 
<pause>something else 
1<pause>2<pause>3<pause> 
Done 

Мой выше тест показывает, что труба будет немедленно отправить любую информацию, которую он получает (при условии, фильтр готов получить его).

Конструкция фидера и/или фильтра может маскировать свободное протекание. У вашего оригинального теста было узкое место в фильтре, поскольку он ждал ввода всех данных перед продолжением. Также возможно, что фидер будет держать вещи вверх. Некоторые программы имеют буферизованный выход. Фидер может не отправлять данные до тех пор, пока буфер не будет заполнен, или буфер не будет сброшен, или поток не будет закрыт.

Существует ряд особенностей поведения, связанных с трубами Windows. Я рекомендую прочитать все ответы на Why does delayed expansion fail when inside a piped block of code? для хорошего обзора многих неинтуитивных проблем.