1. Администрация SafeZone приветствует вас на нашем форуме!
    Если вы больше не желаете видеть рекламу при просмотре тем и сообщений - то достаточно просто зарегистрироваться. Для зарегистрированных пользователей реклама не отображается.
    Если у вас возникли проблемы с регистрацией на форуме - то вы можете сообщить об этом с помощью этой формы без авторизации,администрация форума обязательно отреагирует на вашу проблему.
    Скрыть объявление

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

Тема в разделе "Пакетные файлы CMD, BAT", создана пользователем alex-s, 13 июн 2017.

  1. alex-s

    alex-s Новый пользователь

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

    Код (Text):
    ipconfig
    или

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

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

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

    Код (Text):
    @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 %%
     
     
    Последнее редактирование: 13 июн 2017
  2. Dragokas

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

    Сообщения:
    5.226
    Симпатии:
    5.096
    Здравствуйте, alex-s !
    Добро пожаловать на SafeZone.

    Да, "топорный".
    Токены считаются с единицы.
    Не количество, а порядковые номера токенов, которые будут извлечены из строки и назначены переменным цикла по алфавитному порядку, начиная с буквы, указанной в For %%буква.

    Ну например, вот получение IP:
    Код (Text):

    @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
     
    У меня нету.
    Сделайте:
    Код (Text):

    route print -4 > routes.txt
     
    и пришлите мне файл. И подробности что оттуда брать и куда подставлять. Я в сетке не сильно бум-бум.
     
  3. alex-s

    alex-s Новый пользователь

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

    Код (Text):
    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

    Код (Text):
    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 КБ
      Просмотров:
      3
    • netsh.txt
      Размер файла:
      1,2 КБ
      Просмотров:
      2
    • routes.txt
      Размер файла:
      2,6 КБ
      Просмотров:
      2
    • route-help.txt
      Размер файла:
      3 КБ
      Просмотров:
      1
    Последнее редактирование: 16 июн 2017
  4. Dragokas

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

    Сообщения:
    5.226
    Симпатии:
    5.096
    Всё понятно. Пробуйте:

    Код (DOS):
    @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.

    Работа на Win XP не гарантируется.
    Это уже как-то сами.
    Задержка выставляется, например через:
    Код (Text):
    timeout /t 10 /NOBREAK
    (Vista+) или:
    Код (Text):
    ping 127.1 -n 11
    (XP+)
     
  5. alex-s

    alex-s Новый пользователь

    Сообщения:
    21
    Симпатии:
    1
    Как я понял вы инициализировали переменную %~2 ?
    Назначили начальное значение 0 , эта переменная нужна для подсчета итераций ?

    Код (Text):
    %~2=0

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

    Код (Text):
    %~2+=1
    %~2 - это что название переменой ?
    %~2 - это 2-й аргумент переданныйв :GetStaticRoutes

    :GetStaticRoutes [_out_array_routesBuf] [_out_numberOfRoutesBuf]

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

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

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

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

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

    %~1 - это означает переданный 1-й аргумент "route # " ?
    route # - это что значит ?
    "CntRoutes" - этот аргумент вы назвали "Количество маршрутов" ?
    --- Объединённое сообщение, 19 июн 2017 ---
    Коме того скрипт работает на половину, то есть предлагает выбрать маршрут для удаления, маршрут удаляется , но новый на основании нового IP , не добавляется ????
     
    Последнее редактирование модератором: 19 июн 2017
  6. Dragokas

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

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

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

    alex-s Новый пользователь

    Сообщения:
    21
    Симпатии:
    1
    Пожайлуста посмотрите правильно ли я разобрал процедуру

    :GetStaticRoutes [_out_array_routesBuf] [_out_numberOfRoutesBuf]


    Код (DOS):
    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
    ::  в котором показано выполнение сценария
     

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

    Код (DOS):
    echo Local IP = %ip%
    почему то не может определить.
     
    Последнее редактирование модератором: 22 июн 2017
  8. Dragokas

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

    Сообщения:
    5.226
    Симпатии:
    5.096
    не %~1%, а %~1. Аналогично со вторым.
    на каждой из итераций.
    Двойные проценты - это так:
    Код (Text):
    call echo %%%~2%%
    или так:
    Код (Text):
    call echo %%CntRoutes%%
    В пакетных файлах означает завершить текущую подпрограмму и передать управление следующей команде, следующей после вызова Call,
    или завершить работу текущего пакетного файла, если мы находимся в основной ветви выполнения.

    Всё остальное правильно.
    У меня по вашему демо-файлу нормально определяет.
    Вы батник сохраняли в кодировке OEM-866 ?
    Имя сетевого интерфейса поменяли на своё?
    Код (Text):

    set "adapterName=Ethernet 2"
     
     
    Последнее редактирование: 21 июн 2017
  9. alex-s

    alex-s Новый пользователь

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

    Аргументы всегда обозначаются так %~1, %~2, %~3 , то есть с одним % и т.д - это что стандарт ...
    --- Объединённое сообщение, 22 июн 2017 ---
    Код (Text):
    prompt "$H> "$H
    А вот это непонятно, я пробовал писать с этой командой и без нее, не вижу отличия
    $H> - это перенаправление в $H ?? или что это ??
    Как это работает ???
     
  10. Dragokas

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

    Сообщения:
    5.226
    Симпатии:
    5.096
    Потому что это не переменная, а как вы сами дальше пишите - аргумент.
    В плане set %~1= переменной будет имя, которое раскроется из переданного аргумента.

    Такого у меня в коде нет.

    Для раскрытия аргументов используется символ процента и одна цифра: от %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
    заменяется на полное имя первого найденного
    файла. Если переменная ПУТЬ не определена или
    в результате поиска не найден ни один файл,
    то этот модификатор заменяется на пустую
    строку.
    Несколько модификаторов можно объединять вместе.

    Попробуйте написать тоже самое в окно командной строки.

    Вы процитировали ответ - удаление предыдущего символа.
    > - не является спецсимолом, если заключён в знаки кавычек. $H указан для удаления знаков кавычек.
    В итоге, приглашение командной строки будет выглядеть так:
    вместо стандартного:
    В коде выше используется в косметических целях, когда указан @echo on, следующие за ним команды выводятся на экран при чём вместе со строкой приглашения.
     
  11. alex-s

    alex-s Новый пользователь

    Сообщения:
    21
    Симпатии:
    1
    Вот пожайлуста размышления по по поводу процедуры и вопрос

    :GetIPbyInterface [_in_adapterName] [_out_IPbuf]

    Код (Text):
    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%        
     
     
    Последнее редактирование: 23 июн 2017
  12. alex-s

    alex-s Новый пользователь

    Сообщения:
    21
    Симпатии:
    1
    А для чего вы использовали :jmp0, ведь эта метка нигде не используется ?
    --- Объединённое сообщение, 23 июн 2017 ---
    простите не заметил, понял в чем дело...
     
  13. Dragokas

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

    Сообщения:
    5.226
    Симпатии:
    5.096
    Всё правильно написали.
    & - разделитель команд, если используется однострочник. Хотя в процитированном вами случае действительно код не сломается, если этот знак убрать.
    Если интересно по циклам, можете ещё почитать статью: Статья - Циклические операции и примеры (команда FOR)
     
  14. alex-s

    alex-s Новый пользователь

    Сообщения:
    21
    Симпатии:
    1
    Код (Text):
    :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-вывод на экран ?
    Код (Text):
    echo %n%|>NUL
    >NUL - команда перенаправления стандартного вывода на фиктивное устройство nul, т.е. подавление вывода. - так ???

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

    Код (Text):
    set n=1
    echo %n%|>NUL
    Получаю синтаксическую ошибку, почему ???

    Вот пример

    Код (Text):
    >ping -n 1 comp_name | find /I "TTL"
    Получаю на экран стандартный вывод

    Код (Text):
    >ping -n 1 comp_name | find /I "TTL" > NUL
    Так происходит подавление вывода

    |>NUL - такая конструкция ведь не может работать ?!
    а что она делает в вашем коде ?
     
    Последнее редактирование: 27 июн 2017
  15. Dragokas

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

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

    Полагаю, вы хотели спросить, "почему она работает в моём коде?"
    Ну там, рядом с ней стоит команда findstr. Вот сперва выполняется она, а уж затем >NUL. А сам >NUL не имеет значения, где написан слева или справа от команды.
    Есть ситуации, когда лучше писать её слева, потому что, ближайший к > знак имеет значение, например, 2>NUL - это перенаправление потока # 2 (StdError), поэтому если написать вот так: echo %n%>NUL есть вероятность, что возникнет синтаксическая ошибка.
     
  16. alex-s

    alex-s Новый пользователь

    Сообщения:
    21
    Симпатии:
    1
    Код (DOS):
    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

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


    --- Объединённое сообщение, 27 июн 2017 ---
    Код (DOS):
    echo %n%| findstr /RC:"[^0123456789]" >NUL && goto jmp0
    Не так запутанно для меня (теперь знаю, что в данном случае можно >NUL писать слева от команды)
     
    Последнее редактирование: 27 июн 2017
  17. Dragokas

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

    Сообщения:
    5.226
    Симпатии:
    5.096
    Отдельная процедура не вызывается.
    Call здесь намекает, что будет создан отдельный поток, которому будет передана, например, такая строка:
    Код (Text):

    echo %route # [1]%
     
    т.е. двойные %% по правилам CMD заменяются на одиночные %, а %n% раскрывается в значение переменной n.
    Всё это вместе на языке командных файлов обычно называют "двойным раскрытием переменной", т.е. получение значения переменной, часть имени которой состоит из значения другой переменной.
    Именно поэтому, route # - не является массивом в традиционном понимании языков высокого уровня.
    Это просто совокупность переменных вида:
    и т.д. В коде выше названо как "псевдо-массив".
    --- Объединённое сообщение, 27 июн 2017 ---
    Двойное раскрытие также можно выполнить через:
    Код (Text):

    SetLocal EnableDelayedExpansion
    set n=0
    set "route # [0]=value"
    echo !route # [%n%]!
     
     
Загрузка...

Поделиться этой страницей