在进程完成之前,Windows cmd.exe 中的管道不会转发标准输出? [英] Piping in Windows cmd.exe doesn't forward standard output until the process completes?

查看:40
本文介绍了在进程完成之前,Windows cmd.exe 中的管道不会转发标准输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Windows 命令外壳 cmd.exe 中考虑管道:

Considering pipes in Windows command shell cmd.exe:

C:\>feed | filter

馈送过程的标准输出似乎直到馈送过程运行完成后才能达到过滤过程的标准输入.

The standard output from the feeding process doesn't seem to reach the standard input of the filtering process until AFTER the feeding process runs to completion.

这种类型的缓冲"可能会导致长时间运行的馈送过程的输出消息出现烦人的延迟(您可能希望在早期失败时点击ctrl-c"来中断它).

This type of 'buffering' can cause annoying delays in output messages for long running feeding processes (where you might want to hit 'ctrl-c' to interrupt it on early failure).

有没有办法避免这种情况,以便一旦数据可用,馈送过程的标准输出就会到达过滤过程的标准输入?(无缓冲)

Is there a way to avoid this so that standard output from the feeding process reaches standard input on the filtering process as soon as data is available? (no buffering)

例如下面的简化示例:

feed.bat:

@echo off
echo something
sleep 3
echo something else

filter.bat:

filter.bat:

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

以下命令直到 3 秒后(睡眠完成时)才显示任何内容:

The below command doesn't display anything until after 3 seconds (when the sleep completes):

C:\>feed | filter
_something
_something else

所需的行为是打印_something",然后延迟 3 秒,然后打印_something else".

The desired behavior would be that '_something' is printed, followed by a 3 second delay, followed by '_something else' being printed.

推荐答案

管道在 Windows cmd.exe 中是异步的.在将信息传递到右侧之前,它们不会等待左侧完成.但是您的程序没有证明这一点,原因有两个.

Pipes are asynchronous in Windows cmd.exe. They do not wait for the left side to complete before passing the info to the right. But your program does not demonstrate that for two reasons.

1) FOR/F 命令在 IN() 子句中的命令完成之前不会开始迭代任何行.这适用于所有 FOR/F 变体.IN() 子句的整个结果在迭代任何行之前被缓冲.

1) The FOR /F command does not begin iterating any rows until the command within the IN() clause completes. This is true for all FOR /F variants. The entire result of the IN() clause is buffered before any rows are iterated.

所以你的 filter.bat 不可能展示管道的异步特性.

So your filter.bat couldn't possibly demonstrate the asynchronous nature of pipes.

2) MORE 命令不会写入部分行 - 在打印到标准输出之前,它会等待直到收到换行符.(除非它到达文件末尾).

2) The MORE command will not write partial lines - it waits until it receives a newline character before printing to stdout. (unless it reaches the end of file).

如果您想真正了解管道的异步特性,最好使用一个程序,从 stdin 读取每个字符并立即将其写回 stdout.

If you want to truly see the asynchronous nature of pipes, it is better to use a program that reads each character from stdin and immediately writes it back out to stdout.

这是我的 FEED.BAT 版本 - 它写入多行并多次停顿.它还写入三个没有换行符的字符,每个字符后有一个停顿.

Here is my version of FEED.BAT - it writes multiple lines with multiple pauses. It also writes three characters without linefeed with a pause after each one.

@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 版本 - 它从 stdin 读取一个字符并将其写出到 stdout 直到它到达文件末尾.

Here is my version of FILTER.JS - it reads one character from stdin and writes it out to stdout until it reaches the end of file.

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

这是测试行为的命令

feed | cscript //nologo filter.js

这是输出,只要在更多输出之前有暂停,就会插入 .

And here is the output, with <pause> inserted whenever there is a pause before more output.

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

<小时>

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


My test above demonstrates that a pipe will immediately send any information it receives (assuming the filter is ready to receive it).

进料器和/或过滤器的设计可能会掩盖自由流动的行为.您的原始测试在过滤器中存在瓶颈,因为它在继续之前等待所有输入.进纸器也可以托起东西.一些程序具有缓冲输出.在缓冲区已满、缓冲区已刷新或流关闭之前,馈送器可能不会发送数据.

Design of the feeder and/or filter may mask the free flowing behavior. Your original test had a bottleneck in the filter in that it waited for all input before proceeding. It is also possible for the feeder to hold things up. Some programs have buffered output. The feeder may not send data until the buffer is full, or the buffer is flushed, or the stream closed.

有许多与 Windows 管道相关的特殊行为.我建议阅读 为什么在管道代码块中延迟扩展会失败? 的所有答案非直观问题.

There are a number of peculiar behaviors associated with Windows pipes. I recommend reading all the answers to Why does delayed expansion fail when inside a piped block of code? for a good overview of many non-intuitive issues.

这篇关于在进程完成之前,Windows cmd.exe 中的管道不会转发标准输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆