我尝试打印命令输出的时间(以 ping 为例)。
echo([!time!] start
for /f "usebackq delims= eol=" %%A in (`ping ::1`) do (
echo([!time!] __ %%A
)
echo([!time!] finish
但结果我得到了
[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
看起来循环仅在命令完成后才开始工作。有没有办法在命令完成之前处理命令输出?
FOR/F 不能用于异步处理。
但是可以使用两个线程和一个管道来解决。
生产者线程输出到文件,消费者线程读取所有数据
set /p
,并在发现“EOF”字符串时停止。为了区分真正的“EOF”和程序输出的“EOF”,程序输出通过管道
FIND
在每行前面加上行号。多个
for /L %%n in (1,1,256) do
用于构建(几乎)无限循环,但仍然能够使用命令退出循环goto
(真正的无限循环不能用 goto 停止)。当您使用
for /f
循环时ping ::1
,它会等待命令(在本例中为命令)完成后才开始迭代其输出,这样循环只有在命令完全执行完成后才会获取该命令的输出。这就是导致时间戳为静态的原因,因为循环直到
ping
完成才会运行,因此每次迭代都会获得相同的时间戳。要在仍在运行时处理输出,您必须实时读取输入,而 Batch 并不擅长这一点。我们可以使用的一个好技巧是使用
start
命令异步启动ping
并将输出重定向到我们可以连续读取的临时文件。虽然我的脚本在处理上只是伪实时的,但它比@jeb 的真正的实时处理简单得多,而且它只需要一个线程而不是两个。
如果您需要可靠且实际上异步的实时处理,我推荐使用 @jeb 的生产者-消费者脚本。我没有想到使用这种方法,看过他的脚本后,除了最基本的场景外,这种方法肯定更适合所有场景,但是嘿,这就是我的更简单的脚本绰绰有余的地方 :)