Рассмотрим эту простую серию команд, выполняемых в пакетной среде:
>set ar[0]=orange
>set ar[1]=apple
>set ar[2]=banana
>for %i in (0,1,2) do echo !ar[%i]!
Выводит следующее:
>echo !ar[0]!
!ar[0]!
>!ar[1]!
!ar[1]!
>!ar[2]!
!ar[2]!
Так что это, очевидно, не расширяется до его значений. Как бы я это сделал?
решение1
Источники:
Фаза 5вКак интерпретатор команд Windows (CMD.EXE) анализирует скрипты?
Задержка расширения:Только если включено отложенное расширение, команда не находится вблок в скобках по обе стороны трубы, и команда не является«голый» пакетный скрипт(имя скрипта без скобок, CALL, конкатенация команд или конвейер).
- Каждый токен команды анализируется на предмет отложенного расширения независимо.
- Большинство команд анализируют два или более токенов — токен команды, токен аргументов и каждый токен назначения перенаправления.
- Команда FOR анализирует только токен предложения IN.
- Команда IF анализирует только сравниваемые значения — одно или два, в зависимости от оператора сравнения.
- Для каждого проанализированного токена сначала проверьте, содержит ли он какой-либо
!
. Если нет, то токен не проанализирован — важно для^
символов. Если токен содержит!
, то просканируйте каждый символ слева направо:- Если это символ вставки (
^
), то следующий символ не имеет особого значения, сам символ вставки удаляется. - Если это восклицательный знак, найдите следующий восклицательный знак (знаки препинания больше не наблюдаются), расширьте его до значения переменной.
- Последовательные открытия
!
сворачиваются в одно!
- Все оставшиеся непарные элементы
!
удаляются.
- Последовательные открытия
- Расширение переменных на этом этапе «безопасно», поскольку специальные символы больше не обнаруживаются (даже
<CR>
или<LF>
). - Для более полного объяснения прочтите вторую половину этого от dbenham та же тема - Фаза восклицательного знака
- Если это символ вставки (
Фаза 5.3) Обработка труб:Только если команды находятся на обеих сторонах канала.
Каждая сторона канала обрабатывается независимо и асинхронно.
- Если команда является внутренней для cmd.exe, или это пакетный файл, или если это заключенный в скобки блок команд, то он выполняется в новом потоке cmd.exe через
%comspec% /S /D /c" commandBlock"
, поэтому блок команд получает фазовый перезапуск, но на этот раз в режиме командной строки.- Если это блок команд в скобках, то все
<LF>
, до и после которого есть команда, преобразуются в<space>&
. Остальные<LF>
удаляются.
- Если это блок команд в скобках, то все
- На этом обработка команд конвейера завершена.
- Видетьhttps://stackoverflow.com/q/8192318/1012053для получения дополнительной информации о разборе и обработке каналов
Фаза 5.5) Выполнение перенаправления:Теперь выполняется любое перенаправление, обнаруженное на этапе 2.
- Результаты этапов 4 и 5 могут повлиять на перенаправление, обнаруженное на этапе 2.
- Если перенаправление не удалось, то оставшаяся часть команды прерывается.Обратите внимание, что неудачное перенаправление не устанавливает ERRORLEVEL в 1, если только
||
не используется.
- Вы также можете использовать
Delayed Expansion
кcmd.exe
с флагом[/v:on | /v]
, накомандная строкаили влетучая мышь/cmdфайлы.
- В вашейкомандная строкас использованием
cmd.exe /v:on /c
set ar[0]=orange
set ar[1]=apple
set ar[2]=banana
for %i in (0,1,2) do cmd.exe /v:on /C"echo !ar[%i]!
- В вашейлетучая мышь/cmdфайл без объявления
setlocal enabledelayedexpansion
, вы также можете использоватьcmd.exe /v:on /c "command & command | command || command..."
@echo off
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana"
for %%i in (0,1,2)do cmd /v /c "echo\ !ar[%%i]!"
- В вашейлетучая мышь/cmdдекларирование
setlocal enabledelayedexpansion
:
@echo off
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana"
setlocal enabledelayedexpansion
for %%i in (0,1,2)do echo\ !ar[%%i]!
enndlocal
- Некоторые различия в макете для этоголетучая мышь/cmdкод:
@echo off
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana"
for %%i in (0,1,2)do %ComSpec% /v:on /c"echo !ar[%%i]!"
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana"
setlocal enabledelayedexpansion && for %%i in (0,1,2)do echo\ !ar[%%i]!
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off
set "ar[0]=orange" && set "ar[1]=apple" && set "ar[2]=banana"
for %%i in (0,1,2)do <con: %ComSpec% /v:on /c"echo !ar[%%i]!"
call <con: rem./ && %__APPDIR__%timeout.exe /t -1 && endlocal
- Вы также можете использовать
call
влетучая мышь/cmdили в командной строке, чтобы обновить это значение:
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana"
for %i in (0,1,2)do for %i in (0,1,2)do <con: call echo %ar[%i]%
- В вашейлетучая мышь/cmdфайл или командная строка, все следующие команды одинаковы, соблюдая замену
%i
с%%i
в случае использования влетучая мышь/cmdфайлы
for %i in (0,1,2) do %ComSpec% /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v:on /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v:on /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v:on /c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v /c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/recho !ar[%i]!
for %i in (0,1,2) do %ComSpec%/v/cecho !ar[%i]!
for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!
for %i in (0,1,2) do cmd/v/recho !ar[%i]!
for %i in (0,1,2) do cmd/v/cecho !ar[%i]!
решение2
Отложенное расширение в основном используется для расширения значений переменных более одного раза, особенно в циклах For.
Цитата изhttps://ss64.com/nt/delayedexpansion.html
Отложенное расширение приведет к тому, что переменные в пакетном файле будут расширяться во время выполнения, а не во время анализа. Эта опция включается с помощью команды SETLOCAL EnableDelayedExpansion.
Расширение переменной означает замену переменной (например, %windir%) ее значением C:\WINDOWS
По умолчанию расширение будет происходить только один раз, перед выполнением каждой строки. !Отложенное! расширение выполняется каждый раз при выполнении строки или для каждого цикла в команде цикла FOR. Сначала рассмотрим этот пример:
set i=0
for /l %%a in (0,1,10) do (
set /a i=%i%+1
echo %i%
)
Здесь мы ожидаем, что это выведет числа от 1 до 10. Однако каждый раз будет выведено только 0. Поскольку каждый раз переменные расширяются один раз, поэтому значения не меняются.
На этот раз мы попробуем отложенное расширение:
setlocal enabledelayedexpansion
set i=0
for /l %%a in (0,1,10) do (
set /a i=!i!+1
echo !i!
)
На этот раз мы получим ожидаемый результат, поскольку каждый раз, когда мы расширяем значения, значение изменяется.
Ваш код не работает, потому что вам нужно добавить setlocal enabledelayedexpansion
в начале кода.
надеюсь, это поможет