Замена строки в пакете Windows
Я пытаюсь понять, как замена строк в пакетах Windows на самом деле работает и возникают проблемы.
@echo off
set var=wild
set varnew=%var:l=n%
echo var is: %var%
echo varnew is: %varnew%
работает; он генерирует ожидаемый результат:
var is: wild
varnew is: wind
Но это не так (пример каталога "Главный"):
@echo off
for /D %%G IN (*) do (
setlocal
echo G is: %%G
set _srcp=%%G
echo _srcp is %_srcp%
rem set _newp=%_newp:ai=_01_% <-- confused variable
set _newp=%_srcp:ai=_01_%
echo._newp is: %_newp%
endlocal
)
Он генерирует этот вывод:
G is: Main
_srcp is Main
_newp is: %_srcp:ai=_01_
Я ожидаю, что код будет генерировать _newp is: M_01_n
как последняя строка. У меня действительно нет идей, может кто-нибудь указать мне правильное направление?
BB
2 ответа
У вас есть пара проблем:
%var%
раскрытие происходит, когда оператор анализируется, и весь блок кода в скобках анализируется за один проход, прежде чем какие-либо команды будут выполнены. Таким образом, значение - это значение, которое существовало до запуска цикла. Решение - это отложенное расширение, которое происходит при выполнении каждой команды в цикле.Ваша логика неверна - назначение _newp должно основываться на значении _srcp
Процессор CMD - сложный зверь (и также плохо документированный). Существует множество точек, в которых раскрываются различные типы переменных, и вы должны полностью понимать их, если вы действительно хотите максимально использовать пакетное программирование. Все это объяснено в ссылке, но в итоге порядок расширения такой:
1)% расширения - параметр: echo %1
или переменная окружения: echo %var%
---- Большая часть разбора уже завершена ----
2) ДЛЯ расширения переменной: for %%A in (*) do echo %%A
3) Задержка расширения переменной среды: echo !var!
4) CALL% расширение - параметр: call echo %%1
или переменная окружения: call echo %%var%%
5) Расширение переменной окружения SET /A: `set /a "value=var+1"
Обратите внимание, что отложенное расширение требует, чтобы отложенное расширение было включено через SETLOCAL EnableDelayedExpansion
Следующий код, использующий отложенное расширение, даст искомый результат:
@echo off
for /D %%G in (*) do (
setlocal enableDelayedExpansion
echo G is: %%G
set "_srcp=%%G"
echo _srcp is !_srcp!
set "_newp=!_srcp:ai=_01_!"
echo _newp is: !_newp!
endlocal
)
Обратите внимание, что отложенное расширение происходит после расширения переменной FOR, поэтому результат будет поврежден, если %%G
constains !
, Этого можно избежать с помощью дополнительного SETLOCAL:
for /D %%G in (*) do (
setlocal disableDelayedExpansion
echo G is: %%G
set "_srcp=%%G"
setlocal enableDelayedExpansion
echo _srcp is !_srcp!
set "_newp=!_srcp:ai=_01_!"
echo _newp is: !_newp!
endlocal
endlocal
)
Вы также можете получить желаемый результат, используя CALL с двойным процентом, но это намного медленнее. Скорость не важна, если выполняется несколько раз, но становится очень значительной, если выполняется тысячи раз в цикле.
@echo off
for /D %%G in (*) do (
setlocal
echo G is: %%G
set "_srcp=%%G"
call echo _srcp is %%_srcp%%
call set "_newp=%%_srcp:ai=_01_%%"
call echo _newp is: %%_newp%%
endlocal
)
Далее к ответу Дэйвбенхема
выполнение echo %var% внутри блока, такого как FOR или IF, работает некорректно. Переменные% var% просто не обновляются. Вы должны использовать! Var! и получить! вар! чтобы работать, вы должны установить локальный EnableDelayedExpansion
объяснение этого существует в справке cmd, хотя не очевидно, какая справка команды объясняет это! Это set /?
set /?
Наконец, добавлена поддержка отложенного расширения переменных среды. Эта поддержка всегда отключена по умолчанию, но ее можно включить / отключить с помощью переключателя командной строки /V к CMD.EXE. Смотрите CMD /?
Задержка раскрытия переменных среды полезна для преодоления ограничений текущего раскрытия, которое происходит при чтении строки текста, а не при ее выполнении. В следующем примере демонстрируется проблема с немедленным расширением переменной:
set VAR=before if "%VAR%" == "before" ( set VAR=after if "%VAR%" == "after" @echo If you see this, it worked )
никогда не будет отображать сообщение, поскольку%VAR% в операторах ОБА IF заменяется при чтении первого оператора IF, поскольку оно логически включает в себя тело оператора IF, который является составным оператором. Таким образом, IF внутри составного оператора действительно сравнивает "до" с "после", которое никогда не будет равным. Аналогично, следующий пример не будет работать должным образом:
set LIST= for %i in (*) do set LIST=%LIST% %i echo %LIST%
в том смысле, что он НЕ будет создавать список файлов в текущем каталоге, а вместо этого просто установит для переменной LIST последний найденный файл. Опять же, это связано с тем, что%LIST% раскрывается только один раз при чтении оператора FOR, и в это время переменная LIST пуста. Итак, фактический цикл FOR, который мы выполняем:
for %i in (*) do set LIST= %i
который просто устанавливает LIST для последнего найденного файла.
Задержка раскрытия переменных среды позволяет использовать другой символ (восклицательный знак) для раскрытия переменных среды во время выполнения. Если расширение отложенной переменной включено, приведенные выше примеры могут быть написаны следующим образом, чтобы работать как задумано:
set VAR=before if "%VAR%" == "before" ( set VAR=after if "!VAR!" == "after" @echo If you see this, it worked ) set LIST= for %i in (*) do set LIST=!LIST! %i echo %LIST%
Вы также можете проверить нотацию из командной строки с помощью
cmd /e:on
начиная со значения по умолчанию, cmd / v: off, затем переходя к cmd/v:on. Большинство используют cmd.v: off даже для экспертов (возможно, потому что другие вещи могут интерпретироваться по-разному), поэтому я просто использую это, чтобы показать Вы, что вы можете попробовать! Var! обозначения в CMD с ним.
C:\>set a=5
C:\>echo %a%
5
C:\>echo !a!
!a!
C:\>cmd /v:on
Microsoft Wind
Copyright (c)
C:\>echo !a!
5
C:\>
Кстати, если у вас был cmd/v:on или в командном файле, EnableDelayedExpansion включен, то, как показывает Дейв, вы должны знать! будучи специальным персонажем, так что у вас будет проблема, если! был в пределах%var%. Так что это может быть причиной того, что люди не просто включают режим на полный рабочий день, могут быть и другие причины.