逐行读取标准输入 [英] Read stdin line by line

查看:36
本文介绍了逐行读取标准输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将命令通过管道传输到批处理文件中并进行一些处理,同时保留原始命令的输出.因此,例如在运行以下命令时,输出仍会像根本没有管道一样:

I need to pipe a command into a batch file and do some processing, while preserving the output of the original command. So that for example on running the following command, the output would still be as if there was no piping at all:

ping 127.0.0.1 -n 4 | my_process

目前我发现的最佳解决方法是https://stackoverflow.com/a/6980605/6094503.但我的问题是我需要逐行输出.使用该解决方案,只有在执行完 ping 命令后才会刷新输出.我发现 https://stackoverflow.com/a/21567535/6094503 说这是因为 in(在 for in 循环内).

The best workaround I have found so far is https://stackoverflow.com/a/6980605/6094503. But my problem is that I need the output line by line. Using that solution the output is flushed only after the ping command is done executing. I found https://stackoverflow.com/a/21567535/6094503 which says it is because of the in (inside the for in loop).

这是一行一行的例子:

ping 127.0.0.1 -n 4 | findstr $

实际上,如果 Windows 是一个开源项目,我们可能会在 findstr 或类似命令中找到答案.

Actually if Windows was an open source project we could probably find the answer inside findstr or similar commands.

推荐答案

您可以使用 more 将管道逐行刷新到一个文件中,并使用从该文件中读取的第二个 cmd.exe 实例.

You can flush the pipe line by line with more into a file and with a second cmd.exe instance read from that file.

@echo off
REM *** This is a trampoline to jump to a function when a child process shall be invoked
for /F "tokens=3 delims=:" %%L in ("%~0") do goto %%L

setlocal DisableDelayedExpansion

break > pipe.tmp
REM *** Create a new cmd.exe process, and calling :async in this batch file, uses the trampoline
start "" /b "%~d0\:async:\..%~pnx0"
( 
    more
    echo END
) >> pipe.tmp

REM Wait for a clean exit of the async thread
ping localhost -n 2 > nul
echo END
exit /b

:async
echo async

set lineCnt=0
< pipe.tmp (
    for /L %%n in ( infinite ) do (
    set "line="
    set /p line=
    if defined line (
        set /a lineCnt+=1
        setlocal EnableDelayedExpansion
        if "!line:~0,3!" == "END" (
            exit
        )
        echo( READ[!lineCnt!]: !line!
        endlocal
    )
    )
)

findstr 无法从管道读取并将输出异步存储到文件中.但是它在从文件中读取时有效,但是您需要两个异步进程.

findstr fails to read from a pipe and store the output into a file asynchronously. But it works when reading from a file, but then you need two asynchronous processes.

@echo off
REM *** This is a trampoline to jump to a function when a child process shall be invoked
for /F "tokens=3 delims=:" %%L in ("%~0") do goto %%L

setlocal DisableDelayedExpansion

break > pipe1.tmp
break > pipe2.tmp
REM *** piperun.tmp is used as a signal for :async1 to detect when to stop the infinite loop
break > piperun.tmp

REM *** Create a new cmd.exe process, and calling :async1 in this batch file, uses the trampoline
start "" /b "%~d0\:async1:\..%~pnx0"
start "" /b "%~d0\:async2:\..%~pnx0"

more >> pipe1.tmp
del piperun.tmp

REM Wait for a clean exit of the async thread
ping localhost -n 2 > nul
del pipe1.tmp
del pipe2.tmp

echo END
exit /b


:async1
< pipe1.tmp > pipe2.tmp (
    for /L %%n in ( infinite ) do (
        findstr /n "^"
        if not exist piperun.tmp (
            REM *** The "raw" END is the signal for :async2 to stop the infinite loop
            echo END
            @REM echo EXIT %0 > CON
            exit
        )
    )
)
exit /b

:async2
set lineCnt=0
< pipe2.tmp (
    for /L %%n in ( infinite ) do (
    set "line="
    set /p line=
    if defined line (
        set /a lineCnt+=1
        setlocal EnableDelayedExpansion
        if "!line:~0,3!" == "END" (
            @REM echo EXIT %0 > CON
            exit
        )
        @REM set "line=!line:*:=!"
        echo( READ[!lineCnt!]: !line!
        endlocal
    )
    )
)
exit /b 

这篇关于逐行读取标准输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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