I try to print time of command output(ping as example).
echo([!time!] start
for /f "usebackq delims= eol=" %%A in (`ping ::1`) do (
echo([!time!] __ %%A
)
echo([!time!] finish
but as result I got
[12:37:08.78] start
[12:37:12.04] __ Pinging ::1 with 32 bytes of data:
[12:37:12.04] __ Reply from ::1: time<1ms
[12:37:12.04] __ Reply from ::1: time<1ms
[12:37:12.04] __ Reply from ::1: time<1ms
[12:37:12.04] __ Reply from ::1: time<1ms
[12:37:12.04] __ Ping statistics for ::1:
[12:37:12.04] __ Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
[12:37:12.04] __ Approximate round trip times in milli-seconds:
[12:37:12.04] __ Minimum = 0ms, Maximum = 0ms, Average = 0ms
[12:37:12.04] finish
look like cycle start work only after command finished. Is there a way to process command output before command finished?
The FOR/F can not be used for asynchronous processing.
But it can be solved by using two threads and a pipe.
The producer_thread outputs to a file and the consumer_thread reads all the data with set /p
and stops when it finds an "EOF" string.
To differentiate between the real "EOF" and an "EOF" from program output, the program output is piped through FIND
to prefix each line with a line number.
The multiple for /L %%n in (1,1,256) do
are used to build an (nearly) infinite loop, but still to be able to exit the loop with a goto
command (a really infinite loop can't be stopped with goto).
@echo off
REM *** Trampoline jump for function calls of the form ex. "C:\:functionName:\..\myBatch.bat"
FOR /F "tokens=3 delims=:" %%L in ("%~0") DO goto :%%L
cd. > async.tmp
"%~d0\:producer_thread:\..\%~pnx0" >> async.tmp | "%~d0\:consumer_thread:\..\%~pnx0" < async.tmp
echo END
exit /b
:producer_thread
(
ping ::1 -n 3
echo Test a single EOT
echo EOT
echo Some other output
) | find /n /v ""
(echo EOF)
exit /b
:consumer_thread
setlocal EnableDelayedExpansion
echo([!time!] start
for /L %%n in (1,1,256) do for /L %%n in (1,1,256) do for /L %%n in (1,1,256) do for /L %%n in (1,1,256) do (
set "line="
set /p "line="
if "!line!" == "EOF" goto :exit_loop
if defined line (
set "line=!line:*]=!"
echo([!time!] __ !line!
)
)
:exit_loop
echo([!time!] finish
exit /b