Проверка IP-адреса в пакетном сценарии - сначала сопоставьте с помощью findstr, затем проверьте с помощью циклов for (только с использованием окон, встроенных в функциональность?

Думаю, это вопрос к профессионалам. Кажется, что многие люди спотыкаются о проверке IP-адресов при пакетной обработке, просто используя окна, встроенные в функциональные возможности, но реального кода не найти.

В нескольких местах можно найти выражение findstr для идентификации числовой строки, соответствующей четырем последовательностям чисел.

findstr /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"

Хотя кажется, что нет лучшего способа идентифицировать саму строку (из-за ограниченной поддержки регулярных выражений в findstr), это улавливает слишком ложные срабатывания, такие как 1234.2.3.4 или 999.999.999.999 и, конечно же, 0.0.0.0.

Нужно будет «только» дополнительно проверить найденную строку, например. с последовательностью циклов for и убедитесь, что каждый найденный октет строки действителен для правил IP.

  • первый октет между 1 and 254
  • второй и
  • третий между 0 and 255
  • вперед между 1 and 254

Если затем интегрировать вторую часть проверки в этот код, чтобы определить, был ли найденный IP-адрес одним из 3 частных классов (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 или, если быть точным, одним из: от 10.0.0.0 до 10.255.255.255, от 172.16.0.0 до 172.31.255.255 и 192.168.0.0 до 192.168.255.255) это сделает функцию округления. И не забыть про спец 127.x.x.x надо предупредить D).

Чтобы IP4 завершился, переключитесь, чтобы выбрать, будет ли проверяться частный или общедоступный IP-адрес, а возвращаемые значения могут более точно указать, какой тип или даже маски подсети были распознаны:

  • первый октет должен быть 255
  • второй и
  • третий и
  • четвертый из 0,128,192,224,240,248,252,254,255

Итак, в целом это будет псевдопроцедура:

функция, принимающая ввод, независимо от того, откуда, только для того, чтобы быть вызванной, принимающая переключатель для использования и возвращающая результат

  • использовать коммутаторы для частного или общедоступного диапазона IP-адресов
  • validate IP Syntax
    • IP verification - recognized range and set return values
      • private or
      • общий класс
      • подсеть
      • ...
  • установить возвращаемое значение, установить уровень ошибки в зависимости от переключателя

Если код действительно устанавливает удобные для использования коды возврата (например, возвращает распознанный диапазон IP-адресов), это будет функция на все времена для всех, кто имеет дело с IP4 в любом случае. Хотя я сам расширю эти диапазоны IP-адресов, если только функция будет надежно возвращать эти значения «_return», как в примере кода.

Я что-то забыл?

Никто не кодировал это уже?

РЕШЕНИЕ: В соответствии с примером MC ND и кодом обработки коммутатора и маски подсети Aacini я взорвал код, добавил эхо-обработку ошибок и другие случаи - здесь с включенным тестовым примером кода:

  @echo off
          setlocal enableextensions enabledelayedexpansion

          rem try some ip addresses 
          for %%i in ("1.2.3.4" "0.1.2.3" "250.1024.1.2" "10.0.2.1" "127.0.0.1" "1.2.3.255" "172.16.17.18" "192.168.1.1" "255.128.240.0" "0.0.0.0" "something" "" ) do (
          REM 1.2.3.4 is public / 0.1.2.3 is false all / 10.0.2.1 is private / 127.0.0.1 is local / 172.16.17.18 is private / 192.168.1.1 is private / 255.128.240.0 is subnet / 0.0.0.0 is false all (source net)


              echo --------------- run one as default case assuming pulic with ret var -------------------

              rem call default with a return variable 
              call :validateIP %%~i ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo --------------- run two with switch public -------------------

              rem call with switch public 
              call :validateIP %%~i /public && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run three with switch private ---------------------
              rem call with switch private 
              call :validateIP %%~i /private && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run four with switch private and ret variable ---------------------
              rem call with switch private and return variable
              call :validateIP %%~i /private ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run five with switch local and ret variable ---------------------
              rem call with switch private and return variable
              call :validateIP %%~i /local ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run six with switch subnet and ret variable ---------------------
              rem call with switch private and return variable
              call :validateIP %%~i /subnet ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run seven with switch source and ret variable ---------------------
              rem call with switch private and return variable
              call :validateIP %%~i /source ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run eight with nothing ---------------------
              rem call with switch private and return variable
              call :validateIP && echo is valid || echo is invalid
              echo return value: !ret!
              echo --------------------------------------------

          )   
          exit /b 


 :validateIP ipAddress [/ipRange] [returnVariable]

  rem prepare environment
  setlocal enableextensions enabledelayedexpansion 


  if "%~1"=="" goto USAGE
  echo %~1| findstr /b /e /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" >nul
  if errorlevel 1 goto USAGE
  :afterusage

  rem Initialize ip range as public
  set "ipCASE=public"

  rem Process switches
  set "returnVar=%~2"
  rem If second parameter start with slash...
  if "%returnVar:~0,1%" equ "/" (
      rem It is the /ipRange
      set "ipCASE=%returnVar:~1%"
      set "returnVar=%~3"
  )

  rem asume failure in tests : 0=pass 1=fail : same for return/errorlevel
  set "_return=1"
  set "_returnlevel=1"
  set "subNETNumbers=0,128,192,224,240,248,252,254,255"

  rem test if address conforms to ip address structure
  echo %~1| findstr /b /e /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" >nul

  rem if it conforms to structure, test each octet for range values
  if not errorlevel 1 for /f "tokens=1-4 delims=." %%a in ("%~1") do (
      if %%a gtr 0 if %%a lss 255 if %%b leq 255 if %%c leq 255 if %%d gtr 0 if %%d leq 254 set "_return=public"
      if %%a equ 10 if %%b geq 0 if %%b lss 255 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=private"
      if %%a equ 172 if %%b geq 16 if %%b lss 31 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=private"
      if %%a equ 192 if %%b equ 168 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=private"
      if %%a equ 127 if %%b geq 0 if %%b lss 255 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=local"
      if %%a equ 255 if not "!subNETNumbers:%%b=!" equ "%subNETNumbers%" if not "!subNETNumbers:%%c=!" equ "%subNETNumbers%" if not "!subNETNumbers:%%d=!" equ "%subNETNumbers%" set "_return=subnetmask"
      if %%a equ 0 set "_return=sourcenetwork"
  )

  rem set returnlevels depending on given switch
  if "%ipCASE%"=="public"  if "%_return%"=="public"  (set "_returnlevel=0") else (set "_returnlevel=1")

  if "%ipCASE%"=="private" if "%_return%"=="private" (set "_returnlevel=0") else (set "_returnlevel=1")

  if "%ipCASE%"=="local" if "%_return%"=="local" (set "_returnlevel=0") else (set "_returnlevel=1")

  if "%ipCASE%"=="subnet" if "%_return%"=="subnetmask" (set "_returnlevel=0") else (set "_returnlevel=1")

  if "%ipCASE%"=="source" if "%_return%"=="sourcenetwork" (set "_returnlevel=0") else (set "_returnlevel=1")

  REM OPTION1 set errorlevel
  REM another correct way to set errorlevel would be to REM this line beneath and instead use _returnlevel with exit /b like in line REM OPTION2 - while this is interesting way to set it indirectly
  if "%_returnlevel%"=="0" (ver > nul) else (set dummy 2> nul)


  :endValidateIP
  rem clean and return data/errorlevel to caller
  endlocal & ( if not "%returnVar%"=="" set "%returnVar%=%_return%" ) & exit /b 
  REM OPTION2 endlocal & ( if not "%returnVar%"=="" set "%returnVar%=%_return%" ) & exit /b %_returnlevel%  

  :usage
  echo.
  echo   Usage:  call :validateIP [/ipRange] [returnVariable]
  echo.   
  echo        for example: call :validateIP 127.0.0.2 /local ret 
  echo.   
  echo     if NO switch is given function assumes public, 
  echo     switch and return var are optional
  echo     errorlevel depends and corresponds on given switch
  echo     known switches: /public, /private, /local, /subnet, /source
  echo     return var reflects syntax check, if return var is "1" the input was malformed anyhow
  echo.
  goto :afterusage

person Community    schedule 30.11.2013    source источник
comment
Мне кажется, я должен указать — для полноты картины — что в зависимости от версии Windows, на которой вы работаете, PowerShell также может быть доступен. У вас будет доступ к Regex .NET, а также к другим библиотекам для управления IP-адресами. Это может облегчить эту задачу, если вы сможете это использовать.   -  person chwarr    schedule 30.11.2013
comment
Вы только забыли указать, могут ли строки IP появляться в любом месте внутри строк, возвращаемых findstr...   -  person Aacini    schedule 30.11.2013
comment
@Aacini Я действительно использовал ложную формулировку в первой псевдостроке, обнаружив, что находка использовалась только для проверки синтаксиса октета в первую очередь, как MC ND использовал его тогда в своем коде.   -  person peet    schedule 01.12.2013
comment
@Aacini Не могли бы вы дать мне настоящую функциональную структуру с переключателями лучше, чем я пытался упростить, а не так сказать примитивно :) Тогда я бы заполнил ее IP-определениями? Я застрял с обработкой заданных переменных (предоставленных пользователю) или нет, и случаев.   -  person peet    schedule 14.12.2013
comment
@peet: Извините. Я никоим образом не являюсь экспертом по IP4. Я не знаю таких терминов, как маска подсети, частный или публичный класс и т. д. Конечно, я мог бы изучить эту тему, чтобы понять ваш запрос, но у меня нет причин делать это... Однако, если вы изложите свое задача на простом английском языке и дать точные инструкции по операциям/проверке для каждой части (или группы частей), тогда я думаю, что мог бы написать такой код. Кроме того, я не знаю, что делать с такими запросами, как набор кодов, удобные для использования коды возврата; просто укажите какое значение, которое вы хотите вернуть в каждом случае.   -  person Aacini    schedule 15.12.2013
comment
@Aacini Моя проблема не в том, чтобы закодировать идентификаторы диапазона IP-адресов и установить _return, как в примере кода, - моя проблема состоит в том, чтобы заставить переключатели и возвращаемые значения для работы функции. Также, поскольку обе переменные переключателя и возвращаемого значения должны быть необязательными.   -  person peet    schedule 15.12.2013
comment
@peet: Это НЕ был первоначальный вопрос! Я думаю, что это плохая идея изменить вопрос, чтобы получить ответы на несколько разных проблем в одной и той же теме. В любом случае, смотрите мой новый ответ на ваш новый вопрос ниже... :-(   -  person Aacini    schedule 15.12.2013
comment
@peet: см. также новый метод, добавленный в мой первый ответ.   -  person Aacini    schedule 15.12.2013
comment
Вклад в расширенное регулярное выражение, которое я сделал сам и использую htaccess для блокировки диапазонов IPS, может вам помочь. Regex IP = ([2][5][0-5]|[2][0-4][0-9]|[1][0-9][0-9]|[0][0] [0–9]|[0][1–9][0–9]|[0][0–9][0–9]|[1–9][0–9]|[0][0] -9]|[0-9]\.[2][5][0-5]|[2][0-4][0-9]|[1][0-9][0-9] |[0][0][0-9]|[0][1-9][0-9]|[0][0][0-9][0-9]|[1-9][0-9] ]|[0][0-9]|[0-9]\.[2][5][0-5]|[2][0-4][0-9]|[1][0- 9][0–9]|[0][0][0–9]|[0][1–9][0–9]|[0][0–9][0–9]|[1 -9][0-9]|[0][0-9]|[0-9]\.[2][5][0-5]|[2][0-4][0-9] |[1][0–9][0–9]|[0][0][0–9]|[0][1–9][0–9]|[0][0–9][ 0-9]|[1-9][0-9]|[0][0-9]|[0-9]) AAA.BBB.CCC.DDD   -  person D3F4ULT    schedule 17.12.2013
comment
@ D3F4ULT думаю, я заблудился где-то на разрешении 10-99. хорошее регулярное выражение, что оно на самом деле блокирует? или наоборот, какие диапазоны нужно блокировать на уровне htaccess. большинство вещей, которые я делал, контролировались правилами перезаписи, хотя меня всегда интересовали новые идеи.   -  person peet    schedule 17.12.2013
comment
Некоторые регулярные выражения ненадежны, проверьте эти ‹b›[0–9]{3}‹/b› или ‹b›[0–9]{2}‹/b› или ‹b›[0–9]{1. }‹/b›или ‹b›[0–9]{1,3}‹/b›или ‹b›[0–9]{1,2}‹/b›или ‹b›[0–9] *‹/b›, последнее ‹b›[0-9]*‹/b› неверно, потому что если вы установите числа от 0 до 9, может быть 999 и такого IP нет, правильный способ — представить, что Диапазон IP-адресов от 0 до 255, а также поддиапазоны для размещения регулярного выражения, проверьте эту ссылку, чтобы узнать, сможете ли вы лучше понять правильность этого кода регулярного выражения. pastebin.com/raw.php?i=81XLTdw7   -  person D3F4ULT    schedule 18.12.2013
comment
@ D3F4ULT интересная идея использовать это для htaccess, большое спасибо   -  person peet    schedule 19.12.2013


Ответы (4)


Базовая структура для проверки IP. Адаптируйте по мере необходимости

@echo off
    setlocal enableextensions enabledelayedexpansion

    rem try some ip addresses 
    for %%i in ("1.1.1.1" "0.1.1.1" "250.1024.1.1" "10.0.2.1" "something" "" ) do (

        echo --------------------------------------------

        rem call with a variable to get return value
        call :validateIP %%~i ret 
        echo %%~i : return value : !ret! 

        rem call with or without variable to get errorlevel
        call :validateIP %%~i  && echo %%i is valid || echo %%i is invalid

    )   

    exit /b 

:validateIP ipAddress [returnVariable]
    rem prepare environment
    setlocal 

    rem asume failure in tests : 0=pass 1=fail : same for errorlevel
    set "_return=1"

    rem test if address conforms to ip address structure
    echo %~1^| findstr /b /e /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" >nul

    rem if it conforms to structure, test each octet for rage values
    if not errorlevel 1 for /f "tokens=1-4 delims=." %%a in ("%~1") do (
        if %%a gtr 0 if %%a lss 255 if %%b leq 255 if %%c leq 255 if %%d gtr 0 if %%d leq 254 set "_return=0"
    )

:endValidateIP
    rem clean and return data/errorlevel to caller
    endlocal & ( if not "%~2"=="" set "%~2=%_return%" ) & exit /b %_return%
person MC ND    schedule 30.11.2013
comment
привет, как всегда, вы показываете очень умный код, спасибо, хотя для этого также потребуется часть aacini и переключатели для функции для контроля того, будут ли проверены IP или подсети. не знаю, заставлю ли я все это вместе работать. я тоже зациклен на уровнях ошибок в циклах, помню, у меня было много проблем с ними в моем скрипте для dns-routing-monitor. - person peet; 01.12.2013

нет GNU BRE для проверки точечных IP-адресов. FINDSTRs возможности REGEX ниже этого. Вы можете использовать grep для Windows и GNU ERE:

ECHO(%IP%|GREP -E "(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])"&&ECHO %IP% IS VALID/||%IP% IS NOT A VALID IP.
person Endoro    schedule 30.11.2013
comment
tnx для предложения, хотя часто в корпоративной среде установка программного обеспечения или модулей не допускается - поэтому я должен признать, что делаю это со встроенными функциями Windows. возможно, XHR через JScript мог бы предложить больше функциональности. @rojo как ты думаешь, это возможно? - person peet; 30.11.2013
comment
@peet вместо grep лучше использовать findrepl.bat сценарий Аачини. - person Endoro; 30.11.2013
comment
tnx за предоставление ссылки, очень впечатляющая работа, которую проделал Аачини, и я буду помнить об этом, хотя мне нужно будет прочитать ее еще дважды, чтобы понять это на самом деле :) - person peet; 01.12.2013

Я предположил, что вы хотите просмотреть IP-номера, размещенные внутри текстового файла. Если IP-адреса появляются в фиксированных позициях внутри строк в файле, например, в третьем токене, например:

IP number: 172.16.0.0/12

Затем вы можете извлечь номер IP и разделить его части с помощью команды FOR /F, а затем просмотреть их любым способом:

setlocal EnableDelayedExpansion
set wantedNumbers=0,128,192,224,240,248,252,254,255

for /F "tokens=3" %%n in ('findstr /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" theFile.txt') do (
   for /F "tokens=1-4 delims=./" %%a in ("%%n") do (
      if %%a neq 255 echo First octet is not 255 & goto error
      if "!wantedNumbers:%%b=!" equ "%wantedNumbers%" echo Second octet bad & goto error
      if "!wantedNumbers:%%c=!" equ "%wantedNumbers%" echo Third octet bad & goto error
      if "!wantedNumbers:%%d=!" equ "%wantedNumbers%" echo Fourth octet bad & goto error
      echo The IP %%n is correct
   )
)

Если IP-номера не находятся в фиксированных позициях, вам нужно другое существующее решение.

Однако, если IP-адрес хранится в отдельной переменной (вы не указали этот пункт), просто удалите первый for и замените %%n значением переменной.

ИЗМЕНИТЬ: добавлен новый метод

Редактировать 2: Добавлен список чисел/диапазонов

Я разработал другой способ решения этой проблемы с помощью следующей подпрограммы:

@echo off

rem ValidateIP.bat: Validate an IP4 address
rem Antonio Perez Ayala

if "%~1" neq "" goto validateIP

echo Validate an IP4 address using several successive testings on it
echo/
echo call ValidateIP.bat ipAddress 1:ipRange1 2:ipRange2 ... N:ipRangeN
echo/
echo Each ipRange is comprised of an "errorlevel" followed by a colon and
echo 4 groups separated by dots of anyone of the following:
echo/
echo    - An asterisk, that match any value between 0 and 255.
echo    - A number, that match just that value.
echo    - Two numbers separated by hypen, that match any value in that range.
echo    - A list of numbers and/or ranges separated by number-sign (#).
echo/
echo At end, the value placed before the colon of the *last* matching ipRange
echo is returned in ERRORLEVEL; two or more ipRanges may return the same value.
echo If no ipRange is given, 1:*.*.*.* is assumed.
echo If no ipRange is matched, return zero.
echo/
echo Some examples:
echo/
echo    call ValidateIp %%IPaddress%%  1:0-254.*.*.0-254  2:172.16-30.0-254.1-254
echo/
echo    set subNET=0#128#192#224#240#248#252#254#255
echo    call ValidateIP %%IPaddress%%  1:255.%%subNET%%.%%subNET%%.%%subNET%%
goto :EOF

:validateIP ipAddress [#:ipRange] ...

setlocal EnableDelayedExpansion
echo %~1| findstr /B /E /R "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" > NUL
if errorlevel 1 exit /B 0
for /F "tokens=1-4 delims=." %%a in ("%~1") do set p1=%%a& set p2=%%b& set p3=%%c& set p4=%%d
set "ipRanges=%* "
set ipRanges=%ipRanges:* =%
if not defined ipRanges set ipRanges=1:*.*.*.*
set ipRanges=%ipRanges::*=:0-255%
set ipRanges=%ipRanges:.*=.0-255%
set return=0
for %%a in (%ipRanges%) do for /F "tokens=1,2 delims=:" %%b in ("%%a") do (
   set /A fields=0, i=0
   set ipRange=%%c
   for %%d in ("!ipRange:.=" "!") do (
      set /A this=0, i+=1
      set range=%%~d
      for %%e in ("!range:#=" "!") do for /F "tokens=1-3 delims=-" %%i in ("!i!-%%~e-%%~e") do (
         if !p%%i! geq %%j if !p%%i! leq %%k set this=1
      )
      set /A fields+=this
   )
   if !fields! equ 4 set return=%%b
)
exit /B %return%

Используя предыдущую подпрограмму, эту конкретную проблему можно решить следующим образом:

set "subNET=0#128#192#224#240#248#252#254#255"
call ValidateIp %theIP% 1:0-254.*.*.0-254 2:10.0-254.0-254.0-254 2:172.16-30.0-254.1-254 2:192.168.0-254.0-254 3:127.0-254.0-254.0-254 4:255.%subNET%.%subNET%.%subNET% 5:0.*.*.*

if %errorlevel% equ 1 (
   set ret=public
) else if %errorlevel% equ 2 (
   set ret=private
) else if %errorlevel% equ 3 (
   set ret=local
) else if %errorlevel% equ 4 (
   set ret=subnetmask
) else if %errorlevel% equ 5 (
   set ret=sourcenetwork
) else (
   echo Invalid IP address
   goto :EOF
)

Или вот так короче:

set i=0
for %%a in (public private local subnetmask sourcenetwork) do (
   set /A i+=1
   set result[!i!]=%%a
)

set "subNET=0#128#192#224#240#248#252#254#255"
call ValidateIp %theIP% 1:0-254.*.*.0-254 2:10.0-254.0-254.0-254 2:172.16-30.0-254.1-254 2:192.168.0-254.0-254 3:127.0-254.0-254.0-254 4:255.%subNET%.%subNET%.%subNET% 5:0.*.*.*

if defined result[%errorlevel%] (
   set ret=!result[%errorlevel%]!
) else (
   echo Invalid IP address
   goto :EOF
)
person Aacini    schedule 30.11.2013
comment
привет, сэр, я только что проверил ваш код findrepl, вау, впечатляет, но мне нужно будет прочитать его еще несколько раз, чтобы получить его, если вообще когда-либо :) я полностью игнорировал, откуда будет поступать ввод. одному они понадобятся из файла, другому - из ввода или возврата. поэтому идея заключалась в том, чтобы иметь функцию, которая будет работать с вводом, оставляя получение ввода позади, просто принимая его вызов и проверяя, является ли ввод скорее IP, подсетью или мусором. я использовал ложную формулировку в первой псевдостроке, обнаружив, что находка использовалась только для проверки синтаксиса октета в первую очередь. - person peet; 01.12.2013
comment
Таким образом, MC ND начал возможную структуру для этой функции, в то время как вам потребуется гораздо больше, чтобы принять в ней участие, и больше переключателей для выбора параметров функций, сохраняя при этом функцию в рабочем состоянии. - person peet; 01.12.2013

Это НОВЫЙ ответ на НОВЫЙ вопрос в этой же теме!

Как я уже сказал вам в своем комментарии, мне нужно понять, какова предполагаемая работа кода, чтобы исправить это (иначе, как я мог бы это сделать?), но вы не дали мне ни единого описания вашего NEW< /strong> код, так что могу только догадываться...

Итак, я предполагаю, что подпрограмма :validateIP должна возвращать числовое значение уровня ошибки в вызывающую программу, как описано в команде exit /?, и что она необязательно возвращает строковую переменную в среду вызывающей стороны. Код ниже делает это:

    :validateIP ipAddress [/ipRange] [returnVariable]

    rem prepare environment
    setlocal 

    rem Initialize ip range as public
    set ipCASE=public

    rem Process switches
    set "returnVar=%~2"
    rem If second parameter start with slash...
    if "%returnVar:~0,1%" equ "/" (
        rem It is the /ipRange
        set "ipCASE=%returnVar:~1%"
        set "returnVar=%~3"
    )

echo ipcase: %ipCase%

    rem asume failure in tests : 0=pass 1=fail : same for return/errorlevel
    set "_return=1"
    set "_returnlevel=1"

    rem test if address conforms to ip address structure
    echo %~1| findstr /b /e /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" >nul

    rem if it conforms to structure, test each octet for range values
    if not errorlevel 1 for /f "tokens=1-4 delims=." %%a in ("%~1") do (
        if %%a gtr 0 if %%a lss 255 if %%b leq 255 if %%c leq 255 if %%d gtr 0 if %%d leq 254 set "_return=public"
        if %%a equ 10 if %%b geq 0 if %%b lss 255 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=private"
        if %%a equ 172 if %%b geq 16 if %%b lss 31 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=private"
        if %%a equ 192 if %%b equ 168 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=private"
        if %%a equ 127 if %%b geq 0 if %%b lss 255 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=local"
    )

    rem set errorlevels
    if "%ipCASE%"=="public"  if "%_return%"=="public"  (set "_returnlevel=0") else (set "_returnlevel=1")

    if "%ipCASE%"=="private" if "%_return%"=="private" (set "_returnlevel=0") else (set "_returnlevel=1")

    :endValidateIP
    rem clean and return data/errorlevel to caller
    endlocal & ( if not "%returnVar%"=="" set "%returnVar%=%_return%" ) & exit /b %_returnlevel%     

Однако, когда я протестировал эту подпрограмму с вашим тестовым кодом, я получил странные результаты. Я просмотрела весь код и обнаружила несколько проблем не в подпрограмме, а в тестируемом коде; например, echo %errorlevel% внутри основного цикла for всегда будет показывать 0, а вызов :validateIP ipAddress [/ipRange] [returnVariable] не соответствует этому формату в 3 из 4 случаев и иногда не включает возвращаемую переменную, но вызывающий код всегда показывает ее и т. д. ..

Конечно, эти проблемы не имеют никакого отношения ни к исходной теме этой темы, ни к вашему последнему запросу, и я уже слишком много времени потратил на это дело, поэтому я не решил их...

person Community    schedule 15.12.2013
comment
Не знал, что лучше разбить сложную проблему на несколько вопросов, извините. Будет делать это в будущем. Мое намерение обработать это в одном потоке состояло в том, чтобы сохранить возможность отслеживания для поиска другого пользователя - тогда это будет возможно, связывая вопросы в будущем. Пожалуйста, следуйте своим ответом на новый случай. - person peet; 16.12.2013
comment
новый вопрос здесь - person peet; 16.12.2013
comment
Я добавил описания и эхо, чтобы увидеть вары, а случаи возврата не работают? - person peet; 16.12.2013
comment
Вы были правы, в тестовом коде были ошибки, были строчки, где переключатель стоял перед IP-переменной. Ошибка копирования и вставки, которую я сделал. Я исправил и приношу извинения за вашу путаницу и проблемы, чтобы получить от этого разумную отдачу. Если брать реальный код, то все работает нормально. Я устанавливаю уровень ошибки только с числовым значением 0 или 1, но, поскольку функция принимает разные переключатели, возвращаемый уровень ошибки должен соответствовать установленному переключателю, а не запуску самой функции. Где вы видите другие значения уровня ошибки? - person peet; 17.12.2013
comment
чтобы установить уровень ошибки, это был бы хороший код if "%_returnlevel%"=="0" (ver > nul) else (set dummy 2> nul) почему никто не пишет это так ясно, как есть? в то время как я НЕ устанавливаю какой-либо уровень ошибок напрямую, а Exit /b допускает числовые значения? - person peet; 17.12.2013
comment
Мне нужно было время, чтобы понять ваши опасения. Установка уровня ошибки была совершенно ненужной в моем коде, так как я уже правильно возвращал число по выходу /b. Вы могли бы сказать мне просто REM эту строку, так как она была ненужной. Теперь я использовал правильный способ установки уровня ошибки (как вы показали мой в своей ссылке), в то время как это делает возвращаемый номер выхода ненужным. - person peet; 18.12.2013
comment
Теперь реализовано в обоих направлениях, так как я нахожу это интересным для других. - person peet; 18.12.2013