逐行读取标准输入
Read stdin line by line
我需要将命令通过管道传输到批处理文件中并进行一些处理,同时保留原始命令的输出。因此,例如在 运行 下面的命令中,输出仍然就像根本没有管道一样:
ping 127.0.0.1 -n 4 | my_process
到目前为止我发现的最好的解决方法是 . 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 ,它说这是因为 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
我需要将命令通过管道传输到批处理文件中并进行一些处理,同时保留原始命令的输出。因此,例如在 运行 下面的命令中,输出仍然就像根本没有管道一样:
ping 127.0.0.1 -n 4 | my_process
到目前为止我发现的最好的解决方法是 . 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 ,它说这是因为 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