【问题标题】:What is the reason for error message "(" was unexpected at this time?此时出现错误消息“(”的原因是什么?
【发布时间】:2017-02-20 17:07:25
【问题描述】:

我正在编写一个简单的批处理脚本来 ping 大量 IP 以查看它们是否在线。我写了一些代码,每次运行它,我都会收到一个错误提示

(此时出乎意料。

我不确定我哪里出错了。因此,如果有人能告诉我该怎么做,那就太好了。我是批处理的新手,所以我的代码不是最好的。

::@echo off
color b
title Get Online IPs
for /L %%A IN (0,1,255) do (
    for /L %%B IN (0,1,255) do (
        for /L %%C IN (0,1,255) do (
            for /L %%D IN (0,1,255) do (
                set %%A.%%B.%%C.%%D = IP
                ping -n 1 %%A.%%B.%%C.%%D > ./iptemp.txt
                for /F "delims=" %%i in (iptemp.txt) do set "iptemp=%%i"
                if %iptemp% == "Packets: Sent = 1, Received = 0, Lost = 1 (100% loss)," (
                    echo IP offline
                    goto skip
                )
                echo %IP% >> IPlist.txt
                echo %IP% is online!
                :skip
            )
        )
    )
)

【问题讨论】:

    标签: windows batch-file ip


    【解决方案1】:

    我不明白您为什么要 ping 整个 IPv4 地址范围,即 ping 世界上所有的 IPv4 地址。您知道您尝试 ping 4 294 967 296 个地址吗?

    set %%A.%%B.%%C.%%D = IP 行完全错误。变量的名称和分配给变量的字符串值位于等号的错误一侧。并查看Why is no string output with 'echo %var%' after using 'set var = text' on command line? 以了解为什么等号周围不应有空格。

    每当在以( 开头并以匹配) 结尾的命令块中定义或修改变量并且在同一命令块中引用变量的值时,都需要延迟环境变量扩展。在命令提示符窗口set /? 中运行并阅读所有输出帮助页面以了解有关延迟扩展的详细信息,如下面的代码中使用的那样。

    Windows 命令处理器不支持 FOR 循环中的标签。这里的解决方案是使用 IFELSE

    IF 条件可能永远不会为真,因为比较的是没有双引号的字符串和带双引号的字符串。此处需要使用双引号来进行字符串比较,但不会通过命令 IF 从比较的字符串中删除它们。

    字符串比较的IF条件也是语法错误的原因,因为上面没有首先定义环境变量iptemp FOR,因此在解析命令方块。这导致在大多数外部 FOR 第一次执行之前就已经替换了%iptemp%,导致该行

    if  == "Packets: Sent = 1, Received = 0, Lost = 1 (100 loss)," (
    

    而且这条线当然是完全错误的。注意:单个百分号也被删除。

    要比较的字符串中的百分号必须用另外一个百分号转义,才能解释为文字字符,而不是变量引用的开头。

    在下面最后一行 ECHO 的代码中,感叹号必须用 ^^ 转义才能解释为文字字符,因为启用了延迟扩展,这会从简单的文字改变 ! 的含义字符作为变量名称的分隔符,其值应该在解析命令块时被引用而不扩展。

    @echo off
    setlocal EnableDelayedExpansion
    color b
    title Get Online IPs
    set "ListFile=IPlist.txt"
    if exist "%ListFile%" del "%ListFile%"
    for /L %%A in (0,1,255) do (
        for /L %%B in (0,1,255) do (
            for /L %%C in (0,1,255) do (
                for /L %%D in (0,1,255) do (
                    set "IP=%%A.%%B.%%C.%%D"
                    for /F "delims=" %%i in ('%SystemRoot%\System32\ping.exe -n 1 !IP!') do set "iptemp=%%i"
                    if "!iptemp!" == "Packets: Sent = 1, Received = 0, Lost = 1 (100%% loss)," (
                        echo !IP! is offline.
                    ) else (
                        echo !IP! is online^^!>>"%ListFile%"
                    )
                )
            )
        )
    )
    endlocal
    

    在我的德语 Windows 上,字符串比较永远不会正确,因此所有 IP 都是“在线”的,这当然是错误的。

    最好使用控制台应用程序 PING 的退出代码,成功 ping 时为 0,错误时为 1。先前执行的命令或控制台应用程序的退出代码可以分别使用if errorlevel Xif not errorlevel X 评估,具体取决于检查退出代码(错误级别)是否大于或等于X 或小于X

    @echo off
    setlocal EnableDelayedExpansion
    color b
    title Get Online IPs
    set "ListFile=IPlist.txt"
    if exist "%ListFile%" del "%ListFile%"
    for /L %%A in (0,1,255) do (
        for /L %%B in (0,1,255) do (
            for /L %%C in (0,1,255) do (
                for /L %%D in (0,1,255) do (
                    set "IP=%%A.%%B.%%C.%%D"
                    %SystemRoot%\System32\ping.exe -n 1 !IP! >nul
                    if errorlevel 1 (
                        echo !IP! is offline.
                    ) else (
                        echo !IP! is online^^!>>"%ListFile%"
                    )
                )
            )
        )
    )
    endlocal
    

    要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

    • color /?
    • del /?
    • echo /?
    • endlocal /?
    • for /?
    • if /?
    • ping /?
    • set /?
    • setlocal /?
    • title /?

    另请阅读 Microsoft 文章:

    【讨论】:

      【解决方案2】:
      for /L %%A IN (0,1,255) do (
          for /L %%B IN (0,1,255) do (
              for /L %%C IN (0,1,255) do (
                  for /L %%D IN (0,1,255) do (
                   set "flag="
                   for /F "delims=" %%i in ('ping -n 1 %%A.%%B.%%C.%%D') do (
                    if "%%i" == "Packets: Sent = 1, Received = 0, Lost = 1 (100% loss)," set flag=Y
                   )
                   if defined flag (
                    echo %%A.%%B.%%C.%%D offline
                   ) else (
                    echo %%A.%%B.%%C.%%D >> IPlist.txt
                    echo %%A.%%B.%%C.%%D  is online!
                   )
                  )
              )
          )
      )
      

      {未测试}

      set %%A.%%B.%%C.%%D = IP
      

      将环境变量 0.0.0.0Space .. 255.255.255.255Space 设置为“SpaceIP”的值 空格在标准set 语句中的= 运算符的两边 都很重要 - 您不能简单地颠倒语法并期望cmd 能够理解您的意思。 p>

        for /F "delims=" %%i in (iptemp.txt) do set "iptemp=%%i"
      

      iptemp 的值设置为文件最后一行的内容。它不太可能与您在以后的测试中选择的字符串匹配。

      而且您不能在“块语句”(括号内的语句系列)中使用标签

      此外,正如数千个 SO 响应中所解释的,为了访问块内变量的运行时值,您需要调用 delayedexpansion 模式并使用 !var!。 (还有其他方法——这是最简单的)。 %var%总是变量的值遇到块语句时

      这是您的错误报告的来源 - 实际上“(此时 NOT 预期”。当遇到块时 iptemp 未定义(并且该块是 @987654332 @block), cmd 将此行解释为

      if == "Packets: Sent = 1, Received = 0, Lost = 1 (100% loss)," (
      

      而且无法理解。

      您的“IP 离线”报告会准确地说 - “IP 离线” - 而不是 IP 地址。

      修改后的(但未经测试)代码使用flag作为一袋土豆并将其初始化为 - 封闭的引号确保任何尾随空格都是包含在分配给flag的值中

      for/fping 输出的每一行的全部内容依次传递给%%i,然后将每一行(现在在%%i)与您的魔术字符串进行比较(注意两者 边需要被引用)并且flag 设置为 something - 如果魔术字符串匹配 any 输出行,任何事情都会做

      for/f 结束时,flag当前值 被解释(注意 if defined 作用于 current 值,而不是 初始值)并生成一个或另一个报告。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多