Переменные среды никогда не должны начинаться с цифры, поэтому следует избегать использования цифр для переменных цикла.Запустите в окне командной строки call /?
, и вывод является справкой для этой команды, объясняющей, как на аргументы пакетного файла можно ссылаться с помощью %0
, %1
, %2
, ..., которая объясняет, почему переменные среды с цифрой в качестве первогосимвольные и циклические переменные с цифрой вообще не годятся, даже если значение a%num%
в наборе FOR не ссылается на значение переменной окружения a1
или a2
или a3
или a4
или a5
.Это просто имя переменной среды.Цикл for
совсем не нужен.
@echo off
title var test
:question
set "a1=This"
set "a2=Is"
set "a3=a"
set "a4=Var"
set "a5=Test"
%SystemRoot%\System32\choice.exe /C 12345E /N /M "Press a number in range 1-5 or E for exit: "
if errorlevel 6 goto :EOF
set "num=%ERRORLEVEL%"
set /P "a%num%=Now change the answer: "
echo %a1% %a2% %a3% %a4% %a5%.
call echo You typed: %%a%num%%%
pause
goto question
Командная строка call echo You typed: %%a%num%%%
анализируется командным процессором Windows перед выполнением командной строки с номером 3
, введенным в call echo You typed: %a3%
.Эта командная строка анализируется второй раз из-за команды call
, в результате которой %a3%
заменяется значением переменной среды a3
, поэтому echo
выводит ожидаемую строку.
Это также возможнозаменить call echo You typed: %%a%num%%%
на
setlocal EnableDelayedExpansion
echo You typed: !a%num%!
endlocal
Использование отложенного расширения переменной среды также приводит к двойному анализу командной строки перед выполнением команды echo
.Подробнее см. Как синтаксический анализ сценариев интерпретатора команд Windows (CMD.EXE)?
Прочтите также этот ответ , чтобы узнать подробнее о командах SETLOCAL и ENDLOCAL .
Две строки ниже в коде пакета выше также не очень хороши, учитывая, что пользователь действительно может ввести что угодно.
echo %a1% %a2% %a3% %a4% %a5%.
call echo You typed: %%a%num%%%
Например, если пользователь вводит номер 1
и в следующем приглашении вводит:
Your user name is:& setlocal EnableDelayedExpansion & echo !UserName!& endlocal & rem
Затем пакетный файл делает что-то совершенно иное, чем предназначенное для него, и выводит имя учетной записи пользователя.
Безопасным будет код пакета:
@echo off
title var test
setlocal EnableExtensions DisableDelayedExpansion
:question
set "a1=This"
set "a2=Is"
set "a3=a"
set "a4=Var"
set "a5=Test"
%SystemRoot%\System32\choice.exe /C 12345E /N /M "Press a number in range 1-5 or E for exit: "
if errorlevel 6 goto :EOF
set "num=%ERRORLEVEL%"
set /P "a%num%=Now change the answer: "
setlocal EnableDelayedExpansion
echo !a1! !a2! !a3! !a4! !a5!.
echo You typed: !a%num%!
endlocal
pause
goto question
Теперь строка пользовательского ввода больше не может изменять командные строки, выполняемые процессором команд Windows.
Решение с бесполезным FOR цикл будет выглядеть так:
setlocal EnableDelayedExpansion
for /F tokens^=1-6^ eol^= %%A in ("!a1! !a2! !a3! !a4! !a5! !a%num%!") do echo %%A %%B %%C %%D %%E.&echo You typed: %%F
endlocal
eol=
необходимо вывести все правильно, даже если использовать ввод числа 1
и следующую строку, начинающуюся с точки с запятой.Строка опций FOR не может быть заключена в двойные кавычки в этом случае, например "tokens=1-6 eol="
, потому что это определит "
как символ конца строки, и ничего не выводится, если пользователь вводит число 1
и вводит следующеестрока, начинающаяся с "
.Знак равенства и пробел должны быть экранированы с ^
, чтобы интерпретироваться как буквенные символы с помощью cmd.exe
при двойном анализе всей командной строки for
перед выполнением команды for
.
Примечание. FOR решение цикла не работает корректно при вводе пользователем для первого значения переменной специальной строки командной строки, как указано выше.Так что это тоже не совсем безопасно.