【问题标题】:How can I verify that a string is a valid IPv4 or IPv6 address in batch?如何批量验证字符串是有效的 IPv4 或 IPv6 地址?
【发布时间】:2021-05-16 23:29:56
【问题描述】:

我需要在 Batch 脚本中验证字符串是否是有效的 IPv4 或 IPv6 地址,但显然 Batch 没有简单的方法来解析 IP 地址。

如何在不使用外部工具的情况下批量执行此操作? “外部工具”是指正常 Windows 安装中不存在的东西。

“有效的 IPv4 或 IPv6 地址”是指 IP 地址格式的字符串,带有 999.999.999.999 之类的字符串的误报是可以的(即使欢迎进行一些基本过滤)。根据经验,解决方案至少应该能够区分错误消息和地址。

我知道 similar question 已经存在,但这个问题没有考虑 IPv6,而且它对“有效 IPv4 地址”的定义更加严格(999.999.999.999 之类的地址是不可接受的)。

【问题讨论】:

  • @PedroLobito 如果你不知道,这个问题正在Meta 上讨论,所以你应该在这里表​​达你对这个问题是否应该关闭的意见。此外,缺乏努力绝不是结束问题的理由。
  • 打开一个对 IP 地址要求较低/不正确的新问题看起来很奇怪。在没有任何上下文的情况下,为什么这应该优于已经正确的答案。看起来像一个问题,只是为了适应准备好的答案而构建
  • @jeb 首先,原始问题没有考虑 ipv6。其次,是的,这是一个仅适合准备好的答案的问题。至少在我的理解中,StackOverflow 帮助中心的this 页面鼓励这种行为。
  • 很高兴它再次关闭,即使它重新打开,我相信它会再次关闭。 标题:“如何批量验证字符串是有效的 IPv4 或 IPv6 地址?问题:“误报像 999.999.999.999 这样的字符串是 OK" - 您想验证 IP 地址是否有效,但您认为 999.999.999.999 为 "OK",这对我来说绝对没有意义.

标签: batch-file ip-address ipv6 ipv4 windows-scripting


【解决方案1】:

检查有效的 IPv4:

@if (@X)==(@Y) @end /* JScript comment
    @echo off
    cscript //E:JScript //nologo "%~f0"  %*
    exit /b %errorlevel%
@if (@X)==(@Y) @end JScript comment */
WScript.Quit(ValidateIPaddress(WScript.Arguments.Item(0)));
function ValidateIPaddress(ipaddress) {
 return !(/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress))
}

对于有效的 IPv6 地址:

@if (@X)==(@Y) @end /* JScript comment
    @echo off
    cscript //E:JScript //nologo "%~f0"  %*
    exit /b %errorlevel%
@if (@X)==(@Y) @end JScript comment */
WScript.Quit(ValidateIPaddress(WScript.Arguments.Item(0)));
function ValidateIPaddress(ipaddress) {
 return !(/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/gm.test(ipaddress))
}

两者都依赖于退出代码,因此它们的使用方法如下:

call validIPV4.bat 12.12.12.12 && (
   echo valid ipv4 
) || (
   echo invalid ipv4
)

call validIPV4.bat 12.12.12.6000 && (
  echo valid ipv4 
) || (
  echo invalid ipv4
)

第一个将打印valid ipv4,第二个将打印invalid ipv4

或者您可以检查错误级别:

call validIPV6.bat "1200:0000:AB00:1234:0000:2552:7777:1313"
if %errorlevel% equ 0 ( 
  echo valid ipv6 
) else (
  echo invalid ipv6
)

【讨论】:

  • 您的正则表达式异常复杂。只是对于初学者{7,7}{7} 相同。
  • @OrangeDog - 感谢您的反馈。我对正则表达式不太方便,尽管通常我会设法将它们带入工作状态。如果你想用更好的表达方式添加答案,我会投票。
  • 例如,\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} 将满足 OP 的 IPv4 标准。对于 v6,可能需要一个简单的组。
  • 例如(\p{HexDigit}{4}:){7}\p{HexDigit}{4} 完整的。省略组有点复杂。
【解决方案2】:

经过一些试验(和谷歌搜索)后,我设法编写了一个函数,在 Powershell 的帮助下检查地址的有效性。

该函数要求输入变量名和字符串(括在引号中)。如果字符串是有效 IP,则变量的值设置为True,否则设置为False

set "_ip=127.0.0.1"
call :checkip _result "%_ip%"
echo %_result%

set "_ip=::1/128"
call :checkip _result "%_ip%"
echo %_result%

set "_ip=Not an ip address"
call :checkip _result "%_ip%"
echo %_result%

goto :eof

:checkip
setlocal
set _var=%1
set _ip=%~2
set _prefixlenght=%_ip:*/=%
call set _ip=%%_ip:/%_prefixlenght%=%%
for /F "usebackq tokens=*" %%g in (`powershell -c "$ipaddrobj = [ipaddress]::Any ; if (!([ipaddress]::TryParse('%_ip%', [ref]$ipaddrobj))){if (!([ipaddress]::TryParse('%_ip%'.split(':')[0], [ref]$ipaddrobj))){return $false}} ; return $true"`) do (set _ipvalid=%%g)
endlocal & set %_var%=%_ipvalid%
goto :eof

Powershell 行是对我在评论中找到的 here 的 Powershell 函数的重新改编。

【讨论】:

  • 此答案不符合您自己的标准,即 999.999.999.999 是可接受的输入。
  • @SomethingDark 这不是一个标准,我只是说如果解决方案有像999.999.999.999 这样的误报也没关系。
  • 在您的最后一句话中,您明确列出了不接受 999.999.999.999 作为建议的重复项是不充分的解决方案的原因之一。
  • @SomethingDark 不同的是另一个问题 需要 999.999.999.999 和类似的工件被过滤,而我的接受一些误报。这并不意味着需要将明显无效的地址(如999.999.999.999)识别为有效地址,它只是意味着我的问题的答案不必是“人工输入证明”。我想要的是一种快速检查某些程序/API/等的方法。通常应该输出一个地址的它实际上产生了一个地址,而不是像错误代码这样的东西。
【解决方案3】:

这里尝试使用 Vbscript 使用 RegEx 检查 IPv4 或 IPv6

RegEx Demo Here

Vbscript

Option Explicit
Dim  Title,IP,Array_IP
Title = "Test the validity of an IP address IPv4 Or IPv6"
ForceCScriptExecution(Title)

Array_IP = Array(_
    "1200:0000:AB00:1234:0000:2552:7777:1313",_
    "192.168.1.1",_
    "255.255.0.0",_
    "172.16.18.21",_
    "172.16.18.500",_
    "1600:0000:AB30:1234:0000:2552:7777:1313",_
    "172.16.300.21",_
    "172.16.18.23",_
    "172.256.18.21",_
    "255.255.255.0",_
    "255.255.255.255"_
)

For Each IP in Array_IP
    If Is_Valid(IP) = True Then
        Wscript.echo IP & " is a Valid IP Address"
    Else
        Wscript.echo IP & " is Not a Valid IP Address"
    End if
Next

Wscript.sleep 20000
'------------------------------------------------------------------------------------
Function Is_Valid(ip)
    Dim RegularExpressionObject
    Set RegularExpressionObject = New RegExp
    With RegularExpressionObject
        .Pattern = "(^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$)|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"
        .IgnoreCase = False
        If .Test(ip)= True then
            Is_Valid = True
        end if
    End With
End Function
'------------------------------------------------------------------------------------
Sub ForceCScriptExecution(Title)
    Dim Arg, Str, cmd
    cmd = "CMD /C Title " & Title &" & color 0A & Mode 80,30 & "
    If Not LCase( Right( WScript.FullName, 12 ) ) = "\cscript.exe" Then
        For Each Arg In WScript.Arguments
            If InStr( Arg, " " ) Then Arg = """" & Arg & """"
            Str = Str & " " & Arg
        Next
        CreateObject( "WScript.Shell" ).Run _
           cmd & "cscript //nologo """ & _
            WScript.ScriptFullName & _
            """ " & Str
        WScript.Quit
    End If
End Sub
'-------------------------------------------------------------------------------------

批处理文件:

@echo off
Title Test the validity of an IP address IPv4 Or IPv6
set "_IP=1200:0000:AB00:1234:0000:2552:7777:1313"
Call :CheckIp "%_IP%" Validity
if [%Validity%] equ [0] ( 
    color 0A
    echo "%_IP%" is a valid ip
) else (
    Color 0C
    echo "%_IP%" is not a valid ip
)
Pause
set "_IP=192.168.500.300"
Cls
Call :CheckIp "%_IP%" Validity
if [%Validity%] equ [0] ( 
    color 0A
    echo "%_IP%" is a valid ip
) else (
    Color 0C
    echo "%_IP%" is not a valid ip
)
Pause
Exit
::--------------------------------------------------------------------------------------------------
:CheckIP <IP> <Validity>
Set "VbsFile=%Temp%\%~n0.vbs"
(
    echo WScript.Echo(Is_Valid("%~1"^)^)
    echo Function Is_Valid(ip^)
    echo    Dim RegularExpressionObject
    echo    Set RegularExpressionObject = New RegExp
    echo    With RegularExpressionObject
    echo        .Pattern = "(^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$)|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"
    echo        .IgnoreCase = False
    echo        If .Test(ip^)= True then
    echo            Is_Valid = 0
    echo        Else
    echo            Is_Valid = 1
    echo        End if
    echo    End With
    echo End Function
)>"%VbsFile%"
@for /f "delims=" %%a in ('cscript //nologo "%VbsFile%"') do set "%2=%%a"
Exit /B
::--------------------------------------------------------------------------------------------------

【讨论】:

    【解决方案4】:

    如何在不使用外部工具的情况下批量执行此操作?通过“外 工具”我的意思是普通 Windows 上不存在的东西 安装。

    您可以使用与所有windows计算机捆绑在一起的powershell,即:

    ip_validate.bat

    @echo off
    
    powershell -Command "[ipaddress]::TryParse('192.168.1.1',[ref][ipaddress]::Loopback)"
    powershell -Command "[ipaddress]::TryParse('192.168.1.256',[ref][ipaddress]::Loopback)"
    powershell -Command "[ipaddress]::TryParse('2001:0db8:85a3:0000:0000:8a2e:0370:7334',[ref][ipaddress]::Loopback)"
    powershell -Command "[ipaddress]::TryParse('20ddd01:0db8:85a3:0000:0000:8a2e:0370:7334',[ref][ipaddress]::Loopback)"
    

    输出:

    True
    False
    True
    False
    

    【讨论】:

    • 这最终与 ThePirate42 在他们自己的答案中发布的代码相同。
    • ThePirate42 代码:for /F "usebackq tokens=*" %%g in (`powershell -c "$ipaddrobj = [ipaddress]::Any ; if (!([ipaddress]::TryParse('%_ip%', [ref]$ipaddrobj))){if (!([ipaddress]::TryParse('%_ip%'.split(':')[0], [ref]$ipaddrobj))){return $false}} ; return $true"`) do (set _ipvalid=%%g) 我的代码:powershell -Command "[ipaddress]::TryParse('192.168.1.1',[ref][ipaddress]::Loopback)"
    • 是的,两者都使用[ipaddress]::TryParse,这是答案的核心。
    猜你喜欢
    • 2010-10-22
    • 2023-04-01
    • 2012-06-29
    • 1970-01-01
    • 2014-08-03
    • 2014-12-19
    • 2015-08-06
    • 2011-03-28
    • 2010-10-21
    相关资源
    最近更新 更多