2

在运行确定一组 ping 的平均延迟的批处理时,我遇到了一个不寻常的问题。在将 ping 传送到 FIND 命令时,如果在 ping 中找不到要搜索的字符串,则 FOR 循环不会执行 DO 部分,而是跳到下一次迭代。

以这个命令为例:

FOR /F "tokens=*" %X in ('ping 8.8.8.8 -n 1 -w 1000^|FIND "Average"') do echo Result: %X

如果你把它扔进命令行,你会得到预期的结果:

Result: Minimum = 23ms, Maximum = 23ms, Average = 23ms

对于失败的 ping,我希望看到: 结果:

相反,结果为空。你可以通过在那里扔一个死IP来尝试这个。

FOR /F "tokens=*" %X in ('ping 1.1.1.1 -n 1 -w 1000^|FIND "Average"') do echo Result: %X

在命令从文本文件中迭代 IP 地址的批处理脚本中使用它时,这会给我带来各种破坏。

例如,我有 ip.txt,其中包含 {8.8.8.8,8.8.4.4,1.1.1.1}。当批处理文件循环运行时,我希望输出为:

8.8.8.8 - 23ms
8.8.8.8 - 36ms
1.1.1.1 - 
8.8.8.8 - 20ms
8.8.8.8 - 18ms
1.1.1.1 - 

相反,我得到:

8.8.8.8 - 23ms
8.8.8.8 - 36ms
8.8.8.8 - 20ms
8.8.8.8 - 18ms

FIND 返回的没有值的行会忽略 DO 阶段,而是立即迭代。

我从未见过 FOR 循环忽略 DO 阶段并在之前的任何情况下继续迭代。任何解决方法,甚至只是解释为什么会发生这种情况都会很棒。

谢谢!

EDIT1:哈里·约翰斯顿

感谢您的快速回复。不幸的是,据我所知,这个问题无法在 FOR 循环之外解决。

这适用于单个 IP 示例,但不适用于迭代的多个值。问题是,如前所述,您的示例在所有迭代后只会返回一行,而该行将是最后一次迭代的值。

这更接近正在运行的实际代码。创建一个文本文件名 ip.txt 并用 IP 地址列表填充它,每行一个。

测试.bat

@echo off
cls
if not exist [logs] md [logs]
FOR /F "eol=;" %%i in (ip.txt) do for /f "tokens=9" %%p in ('ping %%i -n 3 -w 1000 ^|FIND "Average"') do echo Result - %%p 
pause

ip.txt

8.8.8.8
1.1.1.1
8.8.4.4

使用您的解决方案,这只会回显 [8.8.4.4] 的 ping 结果。因为它将返回第一个和第三个结果,完成跳过第二个。

EDIT2:德本汉姆

你们太棒了,这很完美!再次感谢您花时间解释问题并提供答案:)

FOR /F "eol=;" %%i in (ip.txt) do for /f "tokens=9" %%p in ('ping %%i -n 3 -w 1000^|find "Average"^|^|echo . . . . . . . . ERROR') do echo Result: %%p
4

2 回答 2

3

这是预期的行为。DO 子句每输出一行执行一次,而 FIND 命令只输出匹配该子句的行,因此只有至少有一行匹配该子句时才会执行 DO 子句。

你可以尝试这样的事情:

set result=No Response
FOR /F "tokens=*" %X in ('ping 1.1.1.1 -n 1 -w 1000^|FIND "Average"') do set result=%X
echo Result: %result%
于 2012-10-25T03:48:41.710 回答
1

Harry Johnston is 100% correct, the behavior you are seeing is exactly as expected. When you PING an invalid address the FIND command is not producing any output so there is nothing to iterate!

You need to modify the IN() clause so that the invalid addresses still produce output. I see 2 simple solutions:

1) Use FINDSTR instead of FIND and search for "Average" and "100% loss". If there are more than 9 tokens then it is an error situation. For this demo I embedded the IP addresses in the script.

@echo off
for %%I in (8.8.8.8 1.1.1.1) do for /f "tokens=9,10" %%A in (
   'ping %%I -n 3 -w 1000^|findstr /c:"Average" /c:"100%% loss"'
) do if "%%B" neq "" (echo %%I  ERROR) else echo %%I  %%A

and here is some sample output:

8.8.8.8  37ms
1.1.1.1  ERROR


2) Use the || operator to conditionally echo a line if FIND fails

for %%I in (8.8.8.8 1.1.1.1) do for /f "tokens=9" %%A in (
    'ping %%I -n 3 -w 1000^|find "Average"^|^|echo . . . . . . . . ERROR'
) do echo %%I  %%A

The output is the same as for the 1st code.


It is also trivial to extend Harry's solution to support a list of IPs. Simply reset the result variable before the inner loop.

setlocal enableDelayedExpansion 
for %%I in (8.8.8.8 1.1.1.1) do (
  set "result=ERROR"
  for /f "tokens=9" %%A in (
      'ping %%I -n 3 -w 1000^|find "Average"'
  ) do set "result=%%A"
  echo %%I  !result!
)

Again, the output is the same.

于 2012-10-25T05:29:43.453 回答