Windows cmd.exe中的pipe道在进程完成之前不会转发标准输出?

考虑Windows命令行cmd.exe中的pipe道:

C:\>feed | filter 

饲喂过程的标准输出似乎没有达到过滤过程的标准input,直到饲喂过程完成后。

这种types的“缓冲”可能会导致长时间运行的进程(在这种情况下,您可能希望在早期失败时按“ctrl-c”来中断它),从而导致输出消息的延迟。

有没有办法避免这种情况,以便在数据可用时,喂养过程的标准输出在过滤过程中达到标准input? (无缓冲)

例如,下面的简化示例:

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”被打印。

管道在Windows cmd.exe中是异步的。 在将信息传递给右侧之前,他们不等待左侧完成。 但是你的程序没有证明这个原因。

1)FOR / F命令不会开始迭代任何行,直到IN()子句中的命令完成。 所有FOR / F变体都是如此。 IN()子句的整个结果在迭代任何行之前被缓冲。

所以你的filter.bat无法证明管道的异步性质。

2)更多的命令不会写部分行 – 它等待,直到它收到一个换行符之前打印到标准输出。 (除非它到达文件的末尾)。

如果你想真正看到管道的异步特性,最好使用一个从stdin中读取每个字符的程序,并立即把它写回标准输出。


这里是我的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>插入<pause>

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

我上面的测试表明,一个管道会立即发送它收到的任何信息(假设过滤器准备好接收它)。

进料器和/或过滤器的设计可能会掩盖自由流动的行为。 您的原始测试在过滤器中存在瓶颈,因此在继续之前等待所有输入。 喂料机也可以把东西拿起来。 有些程序有缓冲输出。 送料器可能不会发送数据,直到缓冲区已满,或缓冲区被刷新,或流关闭。

有许多与Windows管道相关的特殊行为。 我建议阅读所有的答案为什么在管道代码块内部延迟扩展失败? 对许多非直观的问题进行了很好的概述。