逐行读取标准输入

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

ping 127.0.0.1 -n 4 | my_process

到目前为止,我发现的最佳解决方法是/sf/answers/488642381/。但我的问题是我需要逐行输出。使用该解决方案,只有在执行完 ping 命令后才会刷新输出。我发现/sf/answers/1509727481/说这是因为in(在for in循环内)。

这是一行一行的例子:

ping 127.0.0.1 -n 4 | findstr $

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

回答

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

@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无法从管道读取并将输出异步存储到文件中。但是它在从文件中读取时有效,但是您需要两个异步进程。

@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 

  • 我需要一三分钟才能完全欣赏(美丽)`"%~d0:async:..%~pnx0"`。

以上是逐行读取标准输入的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>