脚本忽略退出命令并跳出函数 BATCH/CMD

4
我写的这个脚本旨在从WMIC中解析并提取IP信息。问题在于,当它在只有一个DNS服务器输入的计算机上使用时,脚本会失败。它似乎即使变量DNS2未设置也运行:remove函数,然后:remove函数以我不熟悉的方式失败,并忽略退出命令并跳出函数进入我不想要的脚本部分。以下是有问题的代码,请通过设置您的DNS服务器和索引来测试。脚本需要定义2个DNS服务器才能正常工作,而只有1个则无法正常工作。
@echo off
setlocal enabledelayedexpansion
SETLOCAL ENABLEEXTENSIONS
wmic NICCONFIG where "Index = 1" get /Value | more > storage.txt

for /f "tokens=1-9 delims=,}{=" %%f in (storage.txt) do (
    set cat=%%f
    IF /i !cat!==IPAddress (set IP=%%g)
    IF /i !cat!==IPSubnet (set SUB=%%g)
    IF /i !cat!==DefaultIPGateway (set GW=%%g)
    IF /i !cat!==DNSServerSearchOrder (
        set DNS=%%g
        set DNS2=%%h
    )
    IF /i !cat!==IPEnabled (set enabled=%%g)
    IF /i !cat!==Description (set desc=%%g)
)
if /i %enabled%==True (
if defined IP (
    set item=IP
    CALL :remove
        )
if defined SUB (
    set item=SUB
    CALL :remove
        )
if defined GW (
    set item=GW
    CALL :remove
        )
if defined DNS (
    set item=DNS
    CALL :remove
        )
if defined DNS2 (
    set item=DNS2
    CALL :remove
        )
)
goto :menu
echo SHOULDN'T BE HERE
pause
:::::::::Function to remove quotes::::::::::::::
:remove
for /f tokens^=1^ delims^=^" %%p in (!%item%!) do (
    set !item!=%%p
    rem echo !%item%!
    EXIT /b
    )
echo I BROKE OUT OF THE FUNCTION
pause
:menu
echo I worked!
echo %IP%
echo %SUB%
echo %GW%
echo %DNS1%
if defined DNS2 ( echo %DNS2% )
pause

这里有一个使用LotPings重新设计的另一个例子,需要注意的是,即使没有DNS2,它仍然执行底部的“if defined”语句。

@echo off
SETLOCAL ENABLEEXTENSIONS enabledelayedexpansion
Set Prop=IPAddress IPSubnet DefaultIPGateway DNSServerSearchOrder IPEnabled Description
for /f "tokens=1-9 delims=,}{=" %%f in (
  'wmic NICCONFIG where "Index = 1" get /Value^|findstr /i /B "%Prop%"'
) do (IF /i %%f==IPAddress set "IP=%%~g"
      IF /i %%f==IPSubnet  set "SUB=%%~g"
      IF /i %%f==DefaultIPGateway  set "GW=%%~g"
      IF /i %%f==DNSServerSearchOrder (
        set "DNS=%%~g"
        set "DNS2=%%~h"
      )
      IF /i %%f==IPEnabled   set "enabled=%%~g"
      IF /i %%f==Description set "desc=%%~g"
)
set|Findstr /i /B "IP SUB GW DNS Ena Desc"
echo I worked!
echo %DNS%
echo %DNS2%
if defined DNS2 ( echo DNS2 found, shouldn't have found this)
pause

第二个 for 的选项(tokens,delims)缺少一个开头的双引号。 - Mike Nakis
@MikeNakis 这是使用双引号作为分隔符的唯一正确方式。 - user6811411
不,@MikeNakis,它们不是;这是一种未记录的语法,其中几个字符通过前置“^”进行转义;转义引号“^”以那种方式指定为分隔符... - aschipfl
我一开始尝试用^来转义引号,但没有成功。这个方法是可行的。只有当DNS2没有正确初始化时才会出现问题。如果完全去掉DNS2,这个脚本就可以完美运行。 - Laser411
@LotPings 哇,我不知道那个,谢谢。 - Mike Nakis
@aschipfl 哇,我不知道那个,谢谢。 - Mike Nakis
3个回答

3

编辑:重新设计了批处理,无需使用临时文件:

@echo off
SETLOCAL ENABLEEXTENSIONS enabledelayedexpansion
Set Prop=IPAddress IPSubnet DefaultIPGateway DNSServerSearchOrder IPEnabled Description
for /f "tokens=1-9 delims=,}{=" %%f in (
  'wmic NICCONFIG where "Index = 1" get /Value^|findstr /i /B "%Prop%"'
) do (IF /i %%f==IPAddress set "IP=%%~g"
      IF /i %%f==IPSubnet  set "SUB=%%~g"
      IF /i %%f==DefaultIPGateway  set "GW=%%~g"
      IF /i %%f==DNSServerSearchOrder (
        set "DNS=%%~g"
        set "DNS2=%%~h"
      )
      IF /i %%f==IPEnabled   set "enabled=%%~g"
      IF /i %%f==Description set "desc=%%~g"
)
If "%DNS2:~3%" EQU "" Set "DNS2="
set|Findstr /i /B "IP SUB GW DNS Ena Desc"
echo I worked!
pause

你的意思是没有被分配到任何东西?新的行为是什么?对我来说它仍然失败了,但现在以不同的方式。现在它会先触发一次"I BROKE OUT",然后触发两次"I WORKED!"(别问我怎么做到的 :-/ )。 - Laser411
@Laser411 请看一下重新设计的批处理程序,它消除了删除函数。 - user6811411
问题在于代码还有很多,而那个糟糕的DNS2变量也会在其他地方引起问题。如果没有第二个DNS服务器,我需要了解为什么会出现这种行为。该脚本的这一部分是一个更大的500行脚本的一部分,其中多次调用DNS2。 - Laser411
那个函数是怎么工作的?为什么我的 :remove 函数会以这种方式失败,以至于它能够继续但忽略 EXIT 命令并退出函数?另外,你是如何发现它包含那些十六进制代码的? - Laser411
我已经为你点赞了,但是我的声望还不够高,所以它不会公开显示。你能解释一下 "%DNS2:~3%" 吗? - Laser411
显示剩余9条评论

0

当你遇到这样的问题时,应在任何相关点添加调试信息。
在您的情况下,添加一些echo。

IF /i %%f==DNSServerSearchOrder (
        set "DNS=%%~g"
        set "DNS2=%%~h"
        echo #1 "%%~g"
        echo #2 "%%~h"
        if defined dns echo DNS defined
        if defined dns2 echo DNS2 defined
      )

我得到了类似这样的东西

> #1 "10.51.16.9"
> "2 "
> DNS已定义
> DNS2已定义

正如您所看到的,DNS2已经被定义了,而echo #2 "%%~h"显示了一行被破坏的内容!
原因在于,wmic的行结尾是\r\r\n而不是\r\n
因此,在DNS2中现在有一个单独的\r字符。

您可以使用一个清理函数来从变量中删除所有的\r
这个函数的工作原理是,在通过百分号扩展变量后删除所有的\r(但如果它通过感叹号扩展或者是一个%%p参数,则不会删除)。

:sanitize
set "var=!%1!"
set "%1=%var%"
exit /b

并通过使用它

IF /i %%f==DNSServerSearchOrder (
        set "DNS=%%~g"
        set "DNS2=%%~h"
        call :sanitize DNS
        call :sanitize DNS2
        echo #1 "!DNS!"
        echo #2 "!DNS2!"
        if defined dns echo DNS defined
        if defined dns2 echo DNS2 defined
      )

就是这样了...


0

在解析 wmic 输出的循环周围再包装另一个 for /F 循环:

rem // Code before the loop
for /F "delims=" %%e in ('
    wmic NICCONFIG where "Index = 1" get /Value ^| findstr /I /B "%Prop%"
') do (
    for /F "tokens=1-9 delims=,}{=" %%f in ("%%e") do (
        rem // Code inside of the loop...
    )
)
rem // Code after the loop...

wmic 命令生成了 Unicode 输出,而 for /F 循环未能将其正确转换为 ANSI 文本,导致留下了一些孤立的回车符,这些字符干扰了解析。额外的 for /F 循环以一种通用且可靠的方式去除了这些痕迹。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接