[CMD] Изменение в автоматическом режиме статического маршрута

alex-s

Новый пользователь
Сообщения
21
Реакции
1
Возник вопрос, как написать сценарий , используя только командную строку Windows (паетный файл cmd), проанализировав вывод команд:

Код:
ipconfig

или

Код:
netsh interface ip show address

ПК каждый день получает новый адрес от DHCP.
Стоит задача отфильтровать только адрес определенного адаптера и из него вытянуть IP, данный IP вставить в команду по добавлению статического маршрута.
При этом нужно из команды
Код:
route print -4

отфильтровать постоянные маршруты и запустить проверку, и если маршрут существует, то маршрут будет удален и создается новый, если маршрут - не существует, то просто создается новый маршрут.

Создал сценарий, но он слишком громоздкий и не выполняет в полностью автоматичексом режиме поставленных задач.
В Linux , например, есть утилиты - sed, grep, есть регулярные выражения.
В данном случае я затрудняюсь как в Windows - может подскажите (с пояснениями).
Нет гибкости в фильтровке вывода, а для того чтобы написать управляющую конструкцию для проверки условий, много подводных камней при использовании переменных....

Вот пробный сценарий

Код:
@echo off
setlocal enabledelayedexpansion
echo.
echo -----------------1-----------------
echo.
ipconfig
TIMEOUT /T 5
echo.
for /f "tokens=*" %%i in ('netsh interface ip show address ^| findstr  "172." ^| findstr "IP-адрес"') do set a1=%%i
echo %a1%
TIMEOUT /T 5
:: echo. - символ "точка", после команды echo , позволет убрать лишние сообщения с экрана
echo.
set result2=%a1:~15%
:: выделяем фрагмент текста в строке, с конца строки, на 15 символов
:: как раз такой размер занимает написание IP-адреса
echo %result2%
echo.
TIMEOUT /T 3
echo.
:: удалим пробелы, начиная от начала строки
set gateway=%result2: =%
echo.
echo.
echo -----------------2-----------------
echo.
echo %gateway%
echo.
TIMEOUT /T 2
echo.
route delete 192.168.10.0
echo.
route print -4
TIMEOUT /T 5
echo.
echo -----------------3-----------------
echo.
route add -p 192.168.10.0 MASK 255.255.255.0 %gateway% METRIC 1
echo.
route print -4
echo.
:: символ экранирования '^'
:: tokens=* приводит к тому же результату, что и delims=. Означает прекратить разбивку по
:: разделителю после "0-го" токена, т.е. сразу же.


:: * Этот вариант необходим для работы с файлом, путь или имя которого содержит пробелы.
:: %%i - переменная цикла
:: * маска файлов - это набор файлов, заданный с помощью подстановочных знаков * и/или ?
:: где * - обозначает 0 или больше любых символов в имени файла.
:: а ? - означает 0 или 1 любой символ в имени файла.
:: delims= означает, что в переменную %%i будет записана вся строка (без разделения по пробелу :: или знаку табуляции, т.к. стандартный разделитель заменен на NULL (пустой символ).
:: tokens - количество получаемых токенов (подстрок) в теле цикла и пределы разбивки по
:: разделителю.
:: Также можно задать конкретный № токена, который попадет в первую переменную цикла.
:: * Токены - это подстроки, которые попадают в переменные цикла %% в каждой из итераций.
:: Они получаются в результате разбивки строки, заданной в IN (...), по разделителю, заданному :: в Delims= (по умолчанию, пробел и знак табуляции).

:: В отличие, от FOR без ключа, в FOR /F все токены (все подстроки одной строки) попадают сразу :: В ПЕРВУЮ ИТЕРАЦИЮ цикла.
:: Они будут распределены по РАЗНЫМ переменным цикла, идущим в алфавитном порядке*, начиная с
:: буквы, заданной после FOR /F %%
 
Последнее редактирование:
Здравствуйте, alex-s !
Добро пожаловать на SafeZone.

Нет гибкости в фильтровке вывода
Да, "топорный".
разделителю после "0-го" токена, т.е. сразу же.
Токены считаются с единицы.
tokens - количество получаемых токенов (подстрок) в теле цикла и пределы разбивки по разделителю.
Не количество, а порядковые номера токенов, которые будут извлечены из строки и назначены переменным цикла по алфавитному порядку, начиная с буквы, указанной в For %%буква.

Ну например, вот получение IP:
Код:
@echo off
SetLocal EnableExtensions

set "adapterName=Local 3"

for /f "tokens=2*" %%a in ('netsh interface ip show address ^| findstr /ic:"%adapterName%" /c:"IP-адрес" /c:"IP Address:"') do (
  if defined bAdapterScope ((if "%%a"=="Address:" (set "ip=%%b") else (set "ip=%%a")) & goto jmp1)
  rem Для русской винды
  if /i "%%~b"=="%adapterName%" set bAdapterScope=true
  rem Для английской
  for /f "tokens=1*" %%c in ("%%b") do if /i "%%~d"=="%adapterName%" set bAdapterScope=true
)
:jmp1

echo %ip%

pause

отфильтровать постоянные маршруты
У меня нету.
Сделайте:
Код:
route print -4 > routes.txt
и пришлите мне файл. И подробности что оттуда брать и куда подставлять. Я в сетке не сильно бум-бум.
 
Вот сетевая информация.
Смысл такой:
1. Каждый день происходит смена IP адреса локального компьютера, адрес получается от DHCP-сервера.
2. Динамические маршруты, которые автоматически формирует ОС Windows, не позволяют получить доступ в другую подсеть.
3. Поэтому вручную приходится формировать постоянный маршрут.
4. При добавлении маршрута в одну и ту же подсеть (это подсеть - 192.168.10.0), меняется только адрес шлюза, а этот адрес и есть адрес локального компьютера, который получается от DHCP-сервера.
5. Необходима проверка,что существуют постоянные маршруты (не динамические) причем, чтобы код показывал какие постоянные маршруты на данный момент имеются и написать здесь условие ( например конструкция if-else) :
**************
if
---- если маршруты есть - показать и предложить на выбор удалить маршрут (при этом хорошо бы чтоб по умолчанию, по истечении например 10 с, - удалялся какой-то маршрут , прописанный в сценарии - в моем случае 192.168.10.0 (например, использовать choice, правда я так и не разобрался как эту утилиту можно привязать к данной задаче))
- после команды удаления, следует команда

Код:
route ADD 157.0.0.0 MASK 255.0.0.0  157.55.80.1 METRIC 3 IF 2
             узел^      ^маска      ^шлюз     метрика^    ^

Здесь в качестве значений по умолчанию можно поставить маску 255.255.255.0, и сеть назначения 192.168.10.0

Код:
route add -p 192.168.10.0 MASK 255.255.255.0 %gateway% METRIC 1

%gateway% - это динамический IP - локального компьютера, получаемый от DHCP, в выводе он называется сетевым адаптером - Ethernet adapter Ethernet 2,
эта величина изменяющаяся, и это значение должно браться из вывода конфигурации и подставляться в %gateway%.

****************

- else -
постоянный маршрут отсутствует, идет добавление постоянного маршрута

Вот приблизительно, что хотелось бы видеть от этой задачи.
Конечно Powershell гибче, возможно было бы использовать возможноти vbscrip, но интересует реализация данной задачи только силами Командной строки Windows.
 

Вложения

  • ipconfig.txt
    3.7 KB · Просмотры: 3
  • netsh.txt
    1.2 KB · Просмотры: 2
  • routes.txt
    2.6 KB · Просмотры: 2
  • route-help.txt
    3 KB · Просмотры: 1
Последнее редактирование:
Всё понятно. Пробуйте:

CMD/BATCH:
@echo off
SetLocal EnableExtensions
prompt "$H> "$H

:: задать имя сетевого адаптера
set "adapterName=Local 3"

:: задать статический маршрут для добавления по умолчанию, если в системе не настроено ни одного
set default.IP=192.168.10.0
set default.Mask=255.255.255.0
set default.Metric=1

echo.
echo     //  Управление статическими маршрутами  //
echo.
echo.

call :GetIPbyInterface "%adapterName%" IP
echo Local IP = %ip%
echo.

set GateWay=%IP%

call :GetStaticRoutes "route # " "CntRoutes"

if %CntRoutes%==0 (echo Статических маршрутов не найдено!& goto jmp1)

set route
echo.

:jmp0
set n=0
set /p "n=Введите номер маршрута для замены: "
echo %n%|>NUL findstr /RC:"[^0123456789]" && goto jmp0
if %n% GTR %CntRoutes% goto jmp0
if %n% LEQ 0 goto jmp1

For /f "tokens=1-4" %%a in ('call echo %%route # [%n%]%%') do (
  rem Overwrite
  set default.IP=%%a
  set default.Mask=%%b
  set default.Metric=%%d
)
@echo on
route delete %default.IP%

:jmp1
@echo on
route add -p %default.IP% MASK %default.Mask% %GateWay% METRIC %default.Metric%

@echo off
echo.
pause
goto :eof

:GetIPbyInterface [_in_adapterName] [_out_IPbuf]
  :: получить IP адрес по имени сетевого интерфейса
  for /f "tokens=2*" %%a in ('netsh interface ip show address ^| findstr /ic:"%~1" /c:"IP-адрес" /c:"IP Address:"') do (
    if defined bAdapterScope ((if "%%a"=="Address:" (set "%~2=%%b") else (set "%~2=%%a")) & exit /b)
    if /i "%%~b"=="%~1" set bAdapterScope=true& rem Для русской винды
    for /f "tokens=1*" %%c in ("%%b") do if /i "%%~d"=="%~1" set bAdapterScope=true& rem Для английской
  )
exit /b

:GetStaticRoutes [_out_array_routesBuf] [_out_numberOfRoutesBuf]
  :: создание псевдо-массива статических маршрутов
  set %~2=0
  For /F "delims=" %%a in ('route print -4^| findstr /c:":" /c:"."') do (
    if Defined bPersistentScope (
      set /a %~2+=1
      call set "%~1[%%%~2%%]=%%a"
    )
    if /i "%%a"=="Постоянные маршруты:" set bPersistentScope=true
    if /i "%%a"=="Persistent Routes:" set bPersistentScope=true
  )
exit /b

routes.png


Работа на Win XP не гарантируется.
(при этом хорошо бы чтоб по умолчанию, по истечении например 10 с, - удалялся какой-то маршрут , прописанный в сценарии - в моем случае 192.168.10.0
Это уже как-то сами.
Задержка выставляется, например через:
Код:
timeout /t 10 /NOBREAK
(Vista+) или:
Код:
ping 127.1 -n 11
(XP+)
 
Как я понял вы инициализировали переменную %~2 ?
Назначили начальное значение 0 , эта переменная нужна для подсчета итераций ?

Код:
%~2=0


Здесь после того как цикл FOR прошел один раз, то переменная приращается на 1 шаг.

Код:
%~2+=1

%~2 - это что название переменой ?
%~2 - это 2-й аргумент переданныйв :GetStaticRoutes

:GetStaticRoutes [_out_array_routesBuf] [_out_numberOfRoutesBuf]

А это метка с аргументами ?

:: call :GetStaticRoutes – происходит вызов инструкции расположенной
:: после метки - :GetStaticRoutes
:: и передаются параметры данной инструкции
:: "route # " - входной параметр
:: "CntRoutes" – входной параметр

А как это работает ?

Код:
 call set "%~1[%%%~2%%]=%%a"
- вызов переменной?
%~1[%%%~2%%] - а что это за сочетание ? Разве названия таких переменных бывают ?
Наверное вы просто записали сразу выражение вместо имени переменной ? и назначили его переменной %%a ?

%%a - а где была объявлена эта переменная?

%~1 - это означает переданный 1-й аргумент "route # " ?
route # - это что значит ?
"CntRoutes" - этот аргумент вы назвали "Количество маршрутов" ?
Коме того скрипт работает на половину, то есть предлагает выбрать маршрут для удаления, маршрут удаляется , но новый на основании нового IP , не добавляется ????
 
Последнее редактирование модератором:
%~2 - это что название переменой ?
%~2 - это 2-й аргумент переданный в :GetStaticRoutes
Да, название переменной, переданной во 2-й параметр подпрограммы :GetStaticRoutes
:GetStaticRoutes [_out_array_routesBuf] [_out_numberOfRoutesBuf]
Просто подсказка. Без функционального смысла.
:: call :GetStaticRoutes – происходит вызов инструкции расположенной
:: после метки - :GetStaticRoutes
:: и передаются параметры данной инструкции
:: "route # " - входной параметр
:: "CntRoutes" – входной параметр
да.
Как я понял вы инициализировали переменную %~2 ?
В CMD переменные не нужно (не обязательно) инициализировать.
Обнулил для страховки.
Назначили начальное значение 0 , эта переменная нужна для подсчета итераций ?
Для подсчёта кол-ва маршрутов, и подстановки этого индекса при присвоении значений в псевдомассив.
Здесь после того как цикл FOR прошел один раз, то переменная приращается на 1 шаг.
%~2+=1
Да, прибавляется единица.
route # - это что значит ?
Просто выбрал такое название для переменной.
Если вы про set route #, то это распечатка в консоль всех переменных, название которых начинается, с route #
"CntRoutes" - этот аргумент вы назвали "Количество маршрутов" ?
да.
%%a - а где была объявлена эта переменная?
Это переменная цикла. Соответственно, после For и объявлена.
%~1[%%%~2%%] - а что это за сочетание ? Разве названия таких переменных бывают ?
Наверное вы просто записали сразу выражение вместо имени переменной ? и назначили его переменной %%a ?
Код:
call set "%~1[%%%~2%%]=%%a"
%~1 заменяется на route #
%~2 заменяется на CntRoutes.
%%CntRoutes%% в паре с командой call позволяет раскрыть актуальное значение переменной CntRoutes.
Затем происходит присвоение значения %%a:
set route #[0]=..., set route #[1]=... и т.д. в каждой итерации цикла.

Получить актуальное значение переменной, изменённой в том же или вложенном блоке (цикл, скобки или однострочная команда) можно только через call с двойными процентами, воскл. знаки !переменная!, если включён режим отложенного раскрытия переменных (setLocal Enabledelayedexpansion) или временным выходом за пределы блока. Детальнее читайте: Статья - CMD: SetLocal и расширенная обработка команд
 
Последнее редактирование:
Пожайлуста посмотрите правильно ли я разобрал процедуру

:GetStaticRoutes [_out_array_routesBuf] [_out_numberOfRoutesBuf]


CMD/BATCH:
call :GetStaticRoutes "route # " "CntRoutes"

:: call :GetStaticRoutes – происходит вызов инструкции расположенной
:: после метки - :GetStaticRoutes
:: и передаются параметры данной инструкции
:: "route # " - входной параметр
:: "CntRoutes" – входной параметр
:: вот метка и инструкция за ней

:GetStaticRoutes [_out_array_routesBuf] [_out_numberOfRoutesBuf]
:: создание псевдо-массива статических маршрутов
  set %~2=0
  For /F "delims=" %%a in ('route print -4^| findstr /c:":" /c:"."') do (
    if Defined bPersistentScope (
      set /a %~2+=1
      call set "%~1[%%%~2%%]=%%a"
    )
    if /i "%%a"=="Постоянные маршруты:" set bPersistentScope=true
    if /i "%%a"=="Persistent Routes:" set bPersistentScope=true
  )
exit /b


:: route # - название 1-го аргумента %~1%, то есть имени переменной
:: передаваемой в процедуру
:: "CntRoutes" - название 2-го аргумента %~2%, то есть имени переменной
:: передаваемой в процедуру
:: %~2 - это 2-й аргумент переданный в :GetStaticRoutes
:: %~2 - название переменной, переданной во 2-й параметр подпрограммы
::  :GetStaticRoutes
:: %~2  - эта переменная нужна для подсчёта кол-ва маршрутов, и подстановки
:: этого индекса при присвоении значений в псевдомассив
:: :GetStaticRoutes [_out_array_routesBuf] [_out_numberOfRoutesBuf]
:: Просто подсказка. Без функционального смысла.
:: [_out_array_routesBuf] – выходной массив буфера маршрутов, 2 – й аргумент передаваемый в
:: процедуру  :GetStaticRoutes (получение статических маршрутов)
:: set %~2=0 – устанавливаем начальное значение 2-го аргумента, равное 0, обнуляем
:: значение данной переменной для страховки, от старых значений, которые могли
:: остаться от предыдущих команд
:: [_out_numberOfRoutesBuf_] – номер маршрута в данном буфере
:: For /F  - ключ /F используется для построчного разбора информации
:: "delims=" - означает, что в переменную %%a будет записана вся строка (без
::             разделения по пробелу или знаку табуляции, т.к. стандартный
::             разделитель заменен на NULL (пустой символ).
:: ('route print -4^| findstr /c:":" /c:"."') –вывод данной команды, подлежит
:: построчному разбору
:: ' какое-то выражение ' – одинарные кавычки используются для того,
:: чтобы команда For знала, что данное выражение – это одна команда
:: поэтому разбирается построчно вывод, этой одной большой команды
:: route print -4 – вывод информации о маршрутах протокола IPv4
:: ^ - этот символ, в данном случае, экранирует символ конвейера ' | '
:: findstr /c – команда для поиска и фильтрации слов, фраз , в тексте или файлах
:: /C:строка       Использует заданную строку как искомую фразу поиска.
:: findstr /c:":" – необходимо найти строки содержащие символ ":"
:: findstr /c:"." – необходимо найти строки содержащие символ "."
:: do ( какие-то команды) – выполнить команды, после того как начнется разбор строки
:: if Defined bPersistentScope (
::      set /a %~2+=1
::      call set "%~1[%%%~2%%]=%%a"
::    )
:: Что бы проверить существование переменной, используются операторы if defined (если
:: переменная существует) и if not defined (если переменная не существует):
:: Если переменная bPersistentScope (постоянная_область), тогда выполняем команды в скобках
::    (  set /a %~2+=1
::      call set "%~1[%%%~2%%]=%%a"
::    )
:: Если условие не выполнено, то есть такой переменной в самом начале работы цикла,
:: еще нет, тогда переходим к следующим командам
:: %~2+=1 -  Здесь после того как цикл FOR начал работу и нашел статический маршрут,
::   то переменная приращается на 1 шаг.
:: set /a %~2+=1 – добавим в переменную %~2 (это 2-й аргумент, переданный в процедуру,
:: назвали его – CntRoutes, +1, таким образом мы установили, что сейчас
:: обрабатывается 1-й найденный статический маршрут
:: call set "%~1[%%%~2%%]=%%a"
:: Переменная %~1 заменяется на -  route #, мы передавали это значение 1-м аргументом
:: при вызове процедуры - call :GetStaticRoutes "route # " "CntRoutes"
:: %~2 заменяется на – CntRoutes, мы передавали это значение 2-м аргументом
:: при вызове процедуры - call :GetStaticRoutes "route # " "CntRoutes"
:: %%CntRoutes%% в паре с командой call позволяет раскрыть актуальное значение
:: переменной CntRoutes.
:: [%%%~2%%] – здесь символ 1-го (процента) - % - этот сим обозначает вызов переменной
:: %%~2%% - двойные проценты нужны для получения актуального значения переменной
:: (это актуально только для циклов, вне циклов это не нужн
:: Получить актуальное значение переменной, изменённой в том же или вложенном блоке
:: (цикл, скобки или однострочная команда) можно только через call с двойными процентами,
:: воскл. знаки !переменная!, если включён режим отложенного раскрытия переменных
:: (setLocal Enabledelayedexpansion) или временным выходом за пределы блока.
:: "%~1[%%%~2%%]=%%a , таким образом переменной %~1[%%%~2%%] – происходит присвоение значения
:: содержащегося во временной переменной - %%a, в данном шаге итерации каждого цикла.

:: exit /B  -  ключ /b предписывает завершить текущий пакетный файл-сценарий вместо
:: завершения CMD.EXE. Если текущий пакетный файл-сценарий выполняется вне пакетного файла-
:: сценария, то будет завершена программа CMD.EXE
:: другими словами, если не использовать данный - ключ /b -, то закроется окно cmd
::  в котором показано выполнение сценария

Если статических маршрутов нет, то пакетный файл прерывает работу и ничего не добавляет.
В начале работы он не отображает

CMD/BATCH:
echo Local IP = %ip%

почему то не может определить.
 
Последнее редактирование модератором:
:: route # - название 1-го аргумента %~1%, то есть имени переменной
не %~1%, а %~1. Аналогично со вторым.
[_out_numberOfRoutesBuf_] – номер маршрута в данном буфере
на каждой из итераций.
:: %%~2%% - двойные проценты нужны для получения актуального значения переменной
Двойные проценты - это так:
Код:
call echo %%%~2%%
или так:
Код:
call echo %%CntRoutes%%
В пакетных файлах означает завершить текущую подпрограмму и передать управление следующей команде, следующей после вызова Call,
или завершить работу текущего пакетного файла, если мы находимся в основной ветви выполнения.

Всё остальное правильно.
В начале работы он не отображает
Код:
echo Local IP = %ip%
почему то не может определить.

У меня по вашему демо-файлу нормально определяет.
Вы батник сохраняли в кодировке OEM-866 ?
Имя сетевого интерфейса поменяли на своё?
Код:
set "adapterName=Ethernet 2"
 
Последнее редактирование:
Имя сетевого интерфейса поменяли на своё?

Теперь понятно, я исправил и все заработало, сценарий отрабатывается.
Вопросы еще будут...
Почему иногда переменная вызывается так %~2 , то есть с одним %
Почему иногда вот так %var%, с каждого краю по проценту
Почему установка переменной может быть так - set var=....
Почему установка переменной может быть так - set %var=
В чем здесь отличия ???

Аргументы всегда обозначаются так %~1, %~2, %~3 , то есть с одним % и т.д - это что стандарт ...
Код:
prompt "$H> "$H

А вот это непонятно, я пробовал писать с этой командой и без нее, не вижу отличия
PROMPT [текст] Изменение приглашения командной строки cmd.exe

$H BACKSPACE (удаление предыдущего символа)

$H> - это перенаправление в $H ?? или что это ??
Как это работает ???
 
Почему иногда переменная вызывается так %~2 , то есть с одним %
Потому что это не переменная, а как вы сами дальше пишите - аргумент.
В плане set %~1= переменной будет имя, которое раскроется из переданного аргумента.

Почему установка переменной может быть так - set %var=
Такого у меня в коде нет.

Аргументы всегда обозначаются так %~1, %~2, %~3 , то есть с одним % и т.д - это что стандарт ...
Для раскрытия аргументов используется символ процента и одна цифра: от %1 до %9, то есть этим способом можно раскрыть от первого до девятого аргумента, если не использовать доп. команды, такие как shift, или For.
Все остальные символы между % и цифрой - это знаки модификаторов.
Например ~ означает, что нужно убрать кавычки.
Об остальных модификаторах можно почитать из справки for /?
%~I - из переменной %I удаляются обрамляющие кавычки (")
%~fI - переменная %I расширяется до полного имени файла
%~dI - из переменной %I выделяется только имя диска
%~pI - из переменной %I выделяется только путь к файлу
%~nI - из переменной %I выделяется только имя файла
%~xI - из переменной %I выделяется расширение имени файла
%~sI - полученный путь содержит только короткие имена
%~aI - переменная %I расширяется до атрибутов файла
%~tI - переменная %I расширяется до даты /времени файла
%~zI - переменная %I расширяется до размера файла
%~$ПУТЬ:I - проводится поиск по каталогам, заданным в
переменной среды ПУТЬ, и переменная %I
заменяется на полное имя первого найденного
файла. Если переменная ПУТЬ не определена или
в результате поиска не найден ни один файл,
то этот модификатор заменяется на пустую
строку.
Несколько модификаторов можно объединять вместе.

А вот это непонятно, я пробовал писать с этой командой и без нее, не вижу отличия
Попробуйте написать тоже самое в окно командной строки.

C:\Users\Alex>
C:\Users\Alex>prompt "Hello>"

"Hello>"
$H> - это перенаправление в $H ?? или что это ??
Вы процитировали ответ - удаление предыдущего символа.
> - не является спецсимолом, если заключён в знаки кавычек. $H указан для удаления знаков кавычек.
В итоге, приглашение командной строки будет выглядеть так:
вместо стандартного:
C:\Users\имя пользователя>

В коде выше используется в косметических целях, когда указан @echo on, следующие за ним команды выводятся на экран при чём вместе со строкой приглашения.
 
Вот пожайлуста размышления по по поводу процедуры и вопрос

:GetIPbyInterface [_in_adapterName] [_out_IPbuf]

Код:
call :GetIPbyInterface "%adapterName%" IP

:: call :GetIPbyInterface – происходит вызов инструкции расположенной
:: после метки - :GetIPbyInterface
:: и передаются параметры данной инструкции
:: "%adapterName%" - входной параметр, 1-й передаваемый аргумент
:: уже определен ранее
:: в процедуру :GetIPbyInterface , данное написание %var% - вызов ранее
:: определенной переменной
:: " " – двойные кавычки нужны, если строка содержит пробелы
::  IP  – входной параметр, 2-й передаваемый аргумент
::  еще не определен, но таким образом объявляется, и значение получит уже после обработки
::  в процедуре, в которую данный аргумент передается
:: вот метка и инструкция (процедура) за ней

:GetIPbyInterface [_in_adapterName] [_out_IPbuf]
:: получить IP адрес по имени сетевого интерфейса
  for /f "tokens=2*" %%a in ('netsh interface ip show address ^| findstr /ic:"%~1" /c:"IP-адрес" /c:"IP Address:"') do (
    if defined bAdapterScope ((if "%%a"=="Address:" (set "%~2=%%b") else (set "%~2=%%a")) & exit /b)
    if /i "%%~b"=="%~1" set bAdapterScope=true& rem Для русской винды
    for /f "tokens=1*" %%c in ("%%b") do if /i "%%~d"=="%~1" set bAdapterScope=true& rem Для английской
  )
exit /b


:: [_in_adapterName] [_out_IPbuf] – это подсказки, описывающие назначения
:: передаваемых аргументов в данную процедуру
:: [_in_adapterName] – имя адаптера фигурирующего в выводе команды
:: netsh interface ip show address
:: согласно этому имени, будет разбор строк вывода информации, касательно только
:: этого адаптера
:: [_out_IPbuf] – буфер данных для найденного IP, то есть 2-й аргумент предназначен
:: для хранения полученного значения IP адреса


TOKENS=X,Y,M-N    Определение номеров подстрок, выделяемых из каждой строки файла и передаваемых для выполнения в тело цикла

:: TOKENS=X,Y,M-N  - Определение номеров подстрок, выделяемых из каждой строки файла и
:: передаваемых для выполнения в тело цикла
:: При использовании ключа TOKENS=X,Y,M-N создаются дополнительные переменные.
:: Формат M-N представляет собой диапазон подстрок с номерами от M до N. Если последний
:: символ в строке TOKENS= является звездочкой, то создается дополнительная переменная,
:: значением которой будет весь текст, оставшийся в строке после обработки последней
:: подстроки.

:: FOR /F ["ключи"] %%переменная IN (набор)  DO команда [параметры]
:: ["ключи"] – берутся в двойные кавычки, поэтому "tokens=2*"
:: %%a – явно описана в инструкции, и содержит текущий элемент набора в каждом шаге итерации
:: findstr /ic:"%~1" /c:"IP-адрес" /c:"IP Address:"'
:: ключ /i -  Определяет, что поиск будет вестись без учета регистра
:: "%~1" – ищем строку с 1-м заданным элементом, а именно, сюда в качестве 1-го аргумента
:: передана переменная, которая из "%~1" раскрывается в "%adapterName%", поэтому
:: ищется слово "Ethernet 2"

:: "tokens=2*" – в цикл попадают подстроки , то есть отдельные слова
:: исследуемой строки в данном шаге итерации , начиная со 2-й подстроки в каждой
:: разбираемой строке
:: например, команда -  netsh interface ip show address
:: дает вывод в котором есть строка  - « Настройка интерфейса "Ethernet 2" »
:: и начинается разбор со 2-й подстроки и эта подстрока - «интерфейса», так как
:: она соответствует в  tokens значению 2 , что означает - разбор строки со 2-й подстроки
:: и эта подстрока помещается в переменную %%a
:: в этом же шаге итерации и берется подстрока -  "Ethernet 2"  , она соответствует
:: в  tokens значению  *
:: * - этот символ, сообщает что все остальные подстроки после 2 строки продолжают разбираться
:: и целиком помещаются в переменную  %%b (название переменной, следующей по алфавиту за
:: буквой a
:: при этом перед переменной %%b , ставится  ~ - это знак модификатора ,
:: означает, что нужно убрать кавычки, если найденная подстрока имеет кавычки,
:: таким образом в данном коде переменная будет называться так %%~b

:: как только слово, заключенное в 1-аргументе было найдено, и слово "Ethernet 2"
:: помещено в переменную %%~b , далее происходит поиск , в данном коде мест,
:: где эта переменная проверяется на какое-либо условие
:: или с ней работают какие-либо команды
:: if /i "%%~b"=="%~1" set bAdapterScope=true& rem Для русской локали
:: "%%~b"=="%~1"  - если строки совпадают, тогда устанавливается переменная bAdapterScope
:: которой назначается значение true
:: напоминаю, что это се еще один шаг итерации при разборе какой-то строки

А для чего здесь этот символ & ? -  – Вопрос?

:: новый шаг итерации, разбор строки « IP-адрес       172.16.12.202 »
:: и начинается разбор со 2-й подстроки и эта подстрока - «172.16.12.202», так как
:: она соответствует в  tokens значению 2 , что означает - разбор строки со 2-й подстроки
:: и эта подстрока помещается в переменную %%a
:: далее в коде есть хитрость
:: if defined bAdapterScope ((if "%%a"=="Address:" (set "%~2=%%b") else (set "%~2=%%a")) &
:: exit /b)
:: в этой строке, если переменная %%bAdapterScope%% уже определена (а она
:: была определена в 1-м шаге итерации), то выполняется проверка условий, и "%%a"=="Address:"
:: если не найдено соответствие строк (а оно не будет найдено, так как в данном случае у меня
:: русская локаль в командном интерпретаторе), то выполниться другая ветвь проверки условия –
:: else (set "%~2=%%a") – здесь в передаваемый аргумент (который потом раскроется в коде в
:: переменную %IP% ) - , будет записано, ранее полученное значение при разборе строк,
:: а именно 172.16.12.202, далее знак контактенации &  объединяет предыдущую команду
с командой exit /b – это означает выход из данной процедуры

:: Для английской локали есть небольшое отличие, оно в том, что для разбора строки с
:: с название интерфейса, используется отдельный цикл FOR
:: Для того, чтобы в консоли вывод был на английском, можно выполнить команду chcp 437
:: (правда тогда кириллица в названиях не будет нормально отображаться)
:: обратно вернуть кириллицу в консоль, команда chcp 866

:: Так как в английской локали вывод выглядит вот так
:: « Configuration for interface "Ethernet 2" » , тогда для
::  for /f "tokens=2*" %%a in ('netsh interface ip show address ^| findstr /ic:"%~1" /c:"IP-
:: адрес" /c:"IP Address:"')
:: %%a – это "for" , так как
:: она соответствует в  tokens значению 2 , что означает - разбор строки со 2-й подстроки
:: и эта подстрока помещается в переменную %%a

:: в этом же шаге итерации и берется подстрока -  "Ethernet 2"  , она соответствует
:: в  tokens значению  *
:: * - этот символ, сообщает что все остальные подстроки после 2 строки продолжают разбираться
:: и целиком помещаются в переменную  %%b (название переменной, следующей по алфавиту за
:: буквой a )
:: %%b – это ' interface "Ethernet 2" '

:: кавычки здесь ("%%b") для того, что фраза содержит пробел
:: далее цикл исследует переменную %%b, в которой содержится фраза ' interface "Ethernet 2" '
:: for /f "tokens=1*" %%c in ("%%b") do if /i "%%~d"=="%~1" set bAdapterScope=true& rem Для
:: английской
:: %%c – это « interface »
:: %%~d – это "Ethernet 2" , а модификатор ~ убирает кавычки, когда идет сравнение строк
:: "%%~d"=="%~1" – в случае совпадения , устанавливается переменная bAdapterScope

:: Следующий шаг итерации (для английской локали) – это разбор строки
:: IP Address:              172.16.12.202
:: здесь tokens=2 – это 2-я подстрока « Address: » , то есть
:: %%a – это « Address: »
:: %%b – это « 172.16.12.202 »
:: if "%%a"=="Address:" (set "%~2=%%b") – поэтому выполниться данное условие и в
:: переменную %IP% - , будет помещено значение 172.16.12.202 
:: напомню, что %~2  в коде (вне процедуры) раскроется в переменную %IP%
 
Последнее редактирование:
А для чего вы использовали :jmp0, ведь эта метка нигде не используется ?
А для чего вы использовали :jmp0, ведь эта метка нигде не используется ?
простите не заметил, понял в чем дело...
 
Всё правильно написали.
& - разделитель команд, если используется однострочник. Хотя в процитированном вами случае действительно код не сломается, если этот знак убрать.
Если интересно по циклам, можете ещё почитать статью: Статья - Циклические операции и примеры (команда FOR)
 
Код:
:jmp0
set n=0
set /p "n=Введите номер маршрута для замены: "
echo %n%|>NUL findstr /RC:"[^0123456789]" && goto jmp0
if %n% GTR %CntRoutes% goto jmp0
if %n% LEQ 0 goto jmp1

:: set n=0 – установить переменную n и назначить ей значение 0.
:: n – символизирует введенный пользователем, порядковый номер маршрута
:: set /p "n=Введите номер маршрута для замены: "
:: Ключ /P позволяет установить значение переменной - для входной строки, введенной
:: пользователем. Показывает указанное приглашение promptString перед чтением
:: введенной строки. Приглашение promptString может быть пустым.
:: echo %n% - выводит записанное в переменную %n% - новое значение

А эта констукция должна подавлять echo-вывод на экран ?
Код:
echo %n%|>NUL

>NUL - команда перенаправления стандартного вывода на фиктивное устройство nul, т.е. подавление вывода. - так ???

Но запустив код вот так

Код:
set n=1
echo %n%|>NUL

Получаю синтаксическую ошибку, почему ???

Вот пример

Код:
>ping -n 1 comp_name | find /I "TTL"

Получаю на экран стандартный вывод

Код:
>ping -n 1 comp_name | find /I "TTL" > NUL

Так происходит подавление вывода

|>NUL - такая конструкция ведь не может работать ?!
а что она делает в вашем коде ?
 
Последнее редактирование:
Получаю синтаксическую ошибку, почему ???
Потому что в вашем варианте отсутствует команда, которой вы перенаправляете данные через канал.
В моём варианте эта команда - find.
Если команда отсутствует, то и незачем указывать знак канала |.
>NUL - команда перенаправления стандартного вывода на фиктивное устройство nul, т.е. подавление вывода. - так ???
Перенаправление потока # 1 (StdOutput) на устройство \Device\Null (NUL - это симлинк, можно увидеть, например, в обозревателе объектов Sysinternals WinObj в пространстве имён Global), так что устройство не фиктивное, а вполне реальное, просто не физическое, а виртуальное.
А подавление вывода или нет - это уже конечный результат и будет зависеть от того, какой из потоков вы будете перенаправлять. Если первый, то да - подавление вывода на экран. При этом, операция имеет больший приоритет, чем канал. И от ситуации зависит, например, внутри For /f ('здесь') будет иметь другое значение.

|>NUL - такая конструкция ведь не может работать ?!
а что она делает в вашем коде ?
Полагаю, вы хотели спросить, "почему она работает в моём коде?"
Ну там, рядом с ней стоит команда findstr. Вот сперва выполняется она, а уж затем >NUL. А сам >NUL не имеет значения, где написан слева или справа от команды.
Есть ситуации, когда лучше писать её слева, потому что, ближайший к > знак имеет значение, например, 2>NUL - это перенаправление потока # 2 (StdError), поэтому если написать вот так: echo %n%>NUL есть вероятность, что возникнет синтаксическая ошибка.
 
CMD/BATCH:
For /f "tokens=1-4" %%a in ('call echo %%route # [%n%]%%') do (
rem Overwrite
  set default.IP=%%a
  set default.Mask=%%b
  set default.Metric=%%d
)
@echo on
route delete %default.IP%

:: For /f – построчный разбор вывода команды ('call echo %%route # [%n%]%%')
:: %%route # [%n%]%% - это переменная состоит из 2-x частей
:: route # - данная переменная объявлена была при вызове процедуры
:: call :GetStaticRoutes "route # " "CntRoutes"
:: %n% - эта переменная, появляется в процедуре :jmp0

:: call echo %%route # [%n%]%% - ее вывод такого формата:
:: 193.168.10.0          0.0.0.0          1.1.1.1       1
:: Здесь имеем 4 подстроки
:: "tokens=1-4" – происходит разбор подстрок в диапазоне от 1 до 4

:: set default.IP=%%a -  установили значение маршрута по умолчанию, соответствует переменой
:: %%a – явно объявленной в данном цикле
:: соответственно для подстрок 2, 4 – применяются переменные %%b и %%d
:: переменная %%с , соответствующая 3-й подстроке, в данном случае не используется

Непонятен этот механизм, как происходит это раскрытие, ведь здесь не указано, что нужно вызвать процедуру

call echo %%route # [%n%]%%

но тем не менее получаю строку, такого вида

193.168.10.0 0.0.0.0 1.1.1.1 1

Значит вот так ?


CMD/BATCH:
echo %n%| findstr /RC:"[^0123456789]" >NUL && goto jmp0

Не так запутанно для меня (теперь знаю, что в данном случае можно >NUL писать слева от команды)
 
Последнее редактирование:
Отдельная процедура не вызывается.
Call здесь намекает, что будет создан отдельный поток, которому будет передана, например, такая строка:
Код:
echo %route # [1]%
т.е. двойные %% по правилам CMD заменяются на одиночные %, а %n% раскрывается в значение переменной n.
Всё это вместе на языке командных файлов обычно называют "двойным раскрытием переменной", т.е. получение значения переменной, часть имени которой состоит из значения другой переменной.
Именно поэтому, route # - не является массивом в традиционном понимании языков высокого уровня.
Это просто совокупность переменных вида:
и т.д. В коде выше названо как "псевдо-массив".
Двойное раскрытие также можно выполнить через:
Код:
SetLocal EnableDelayedExpansion
set n=0
set "route # [0]=value"
echo !route # [%n%]!
 
Назад
Сверху Снизу