Что исправить в моем коде с двумя условиями IF внутри цикла FOR, ссылающимися на переменную среды, определенную условиями IF? - PullRequest
0 голосов
/ 29 сентября 2018

Не могли бы вы подсказать мне, как исправить мой скрипт, чтобы получить результаты трассировки маршрута для некоторых IP-адресов?

Я хочу получить tracert результаты для 8.8.8.8 и 8.8.4.4 .Я написал скрипт ниже, и он отлично работает:

@echo off
echo %date% %time%

SET DNS1=8.8.8.8
SET DNS2=8.8.4.4

for  %%i in (%DNS1% %DNS2%) do (
    echo ----------------
    echo tracert to %%i
    tracert -d %%i
)

echo %time%
exit

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

@echo off
echo %date% %time%

SET DNS1=8.8.8.8
SET DNS2=8.8.4.4

for  %%i in (%DNS1% %DNS2%) do (
    echo ----------------
    if (%%i == 8.8.8.8 set host=Google1
        %%i == 8.8.4.4 set host=Google2)
    echo tracert to %host%
    tracert -d %%i
)

echo %time%
exit

Может кто-нибудь исправить код для меня?

Ответы [ 2 ]

0 голосов
/ 29 сентября 2018

Пакетный файл может быть записан так:

@echo off
echo %DATE% %TIME%

setlocal EnableExtensions EnableDelayedExpansion
set "DNS1=8.8.8.8"
set "DNS2=8.8.4.4"

for %%i in (%DNS1% %DNS2%) do (
    echo ----------------
    if %%i == 8.8.8.8 set "host=Google1"
    if %%i == 8.8.4.4 set "host=Google2"
    echo tracert to !host!
    tracert -d %%i
)

endlocal
echo %TIME%
exit /B

Командный процессор Windows выполняет одну командную строку за другой.Как синтаксический анализ командной строки перед выполнением описан в Как синтаксический анализ сценариев интерпретатора команд Windows (CMD.EXE)? Что в конечном итоге выполняется после анализа командной строки, можно увидеть при выполнении пакетного файла без @echo off из окна командной строки, как описано в отладка командного файла .

Блок команд, начинающийся с ( и заканчивающийся соответствием ), полностью анализируется cmd.exeперед выполнением команды делает условное или безусловное использование командного блока.Во время синтаксического анализа командного блока все ссылки на переменные среды, использующие синтаксис %variable% наподобие %host%, заменяются текущим значением указанной переменной среды.В этом случае %host%, скорее всего, заменяется пустой строкой до того, как FOR вообще будет выполнен, если переменная окружения host не определена случайно при запуске пакетного файла.

Вывод справки при запуске set /? в окне командной строки объясняет, когда и как использовать отложенное расширение на примере IF и FOR .В приведенном выше коде расширение переменной среды с задержкой включено и используется для ссылки на текущее значение переменной среды host на итерациях блока команд тела цикла, для которого определяется переменная среды и ей присваивается строковое значение.

Также можно было бы использовать:

@echo off
echo %DATE% %TIME%

setlocal EnableExtensions DisableDelayedExpansion
set "DNS1=8.8.8.8"
set "DNS2=8.8.4.4"

for %%i in (%DNS1% %DNS2%) do (
    echo ----------------
    if %%i == 8.8.8.8 set "host=Google1"
    if %%i == 8.8.4.4 set "host=Google2"
    call echo tracert to %%host%%
    tracert -d %%i
)

endlocal
echo %TIME%
exit /B

Командная строка call echo tracert to %%host%% изменяется на этапе синтаксического анализа всего командного блока командным процессором Windows на call echo tracert to %host% и из-за команды CALL эта командная строка анализируется второй раз при каждом выполнении командного блока перед выполнением команды ECHO , в результате чего в консольное окно выводится текущее значение переменной среды host.

Но я предлагаю использовать этот гораздо лучший код:

@echo off
echo %DATE% %TIME%
echo/

setlocal EnableExtensions DisableDelayedExpansion
set "DNS1=8.8.8.8=Google1"
set "DNS2=8.8.4.4=Google2"

for /F "tokens=2* delims==" %%I in ('set DNS 2^>nul') do (
    echo ----------------
    echo tracert to %%J
    echo %SystemRoot%\System32\tracert.exe -d %%I
)

endlocal
echo/
echo %TIME%
exit /B

Один или несколько IP-адресов и их имена хостов назначаются одной или нескольким переменным среды, начинающимся со строки DNS.IP-адрес и имя хоста разделяются знаком равенства.

Команда FOR выполняется в отдельном командном процессе, запущенном с cmd.exe /C в фоновом режиме командной строки:

set DNS 2>nul

Команда SET выводит для обработки STDOUT (стандартный вывод) все переменные среды, начиная с DNS, отсортированные в алфавитном порядке с name=value, что означает для этого примера:

DNS1=8.8.8.8=Google1
DNS2=8.8.4.4=Google2

Сообщение об ошибке, выводимое SET для обработки STDERR (стандартная ошибка) при отсутствии поиска переменной среды, начинающейся со строки DNS, будет подавлено этим кодом путем перенаправленияэто на устройство NUL .

Прочтите также статью Microsoft о Использование операторов перенаправления команд для объяснения 2>nul.Оператор перенаправления > должен быть экранирован с помощью символа вставки ^ в командной строке FOR , чтобы интерпретироваться как литеральный символ, когда интерпретатор команд Windows обрабатывает эту командную строку перед выполнением команды FOR , котораявыполняет встроенную командную строку set в отдельном командном процессе, запущенном в фоновом режиме.

FOR с использованием опции /F захватывает все выходные данные для обработки STDOUT в фоновом режимеКоманда обрабатывает и обрабатывает эти выходные данные, игнорируя пустые строки и строки, начинающиеся с точки с запятой.

Все захваченные строки начинаются с DNS, и поэтому определенно не игнорируется ни одна строка, поскольку ни одна строка не начинается с ;.

FOR с использованием опции /F также будет разбивать каждую строку на подстроки с использованием пробела / табуляции в качестве разделителя с назначением только первой подстроки указанной переменной цикла I.Но такое поведение разделения строк бесполезно для этой задачи.

По этой причине строка параметров "tokens=2* delims==" переопределяет поведение разделения строк.Теперь = используется в качестве разделителя между строками вместо пробела и табуляции.

И вместо назначения первой строки = с разделителями для переменной цикла I, которая будет именем переменной среды,вторая строка с разделителями со знаком равенства назначается переменной цикла I из-за tokens=2, который является IP-адресом.

И дополнительно назначается следующей переменной цикла J в соответствии с таблицей ASCII остаток строки после знака (ов) после второй = строки с разделителями без дальнейшего разделения строки на знак равенства.Таким образом, имя хоста присваивается переменной цикла J, даже если она содержит один или несколько =, если они не содержатся в начале имени хоста.

Этот код, очевидно, лучше, чем DNSПеременные среды могут быть определены в верхней части пакетного файла с IP-адресом и именем хоста, и ничего не должно быть изменено в командной строке ниже, потому что он просто обрабатывает от 0 до n переменных среды, начиная с DNS и имея по крайней мере секунду = подстрока с разделителями.

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

  • call /?
  • echo /?
  • endlocal /?
  • exit /?
  • for /?
  • if /?
  • set /?
  • setlocal /?
  • tracert /?
0 голосов
/ 29 сентября 2018

В этом коде используется правильное использование для проверки нескольких условий с помощью команды IF.В качестве лучшей практики я всегда использую кавычки вокруг сравнения строк.Также обратите внимание на использование отложенного расширения с переменной host.Это необходимо, поскольку вы создаете переменную внутри блока кода, заключенного в скобки.

@echo off
setlocal enabledelayedexpansion

echo %date% %time%

SET DNS1=8.8.8.8
SET DNS2=8.8.4.4

for  %%i in (%DNS1% %DNS2%) do (
    echo ----------------
    if "%%i"=="8.8.8.8" set host=Google1
    if "%%i"=="8.8.4.4" set host=Google2
    echo tracert to !host!
    tracert -d %%i
)

echo %time%
endlocal
exit
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...