2

Я пытаюсь понять, как замена строк в пакетах 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

Но это не так (пример каталога "Main"):

@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 ответа2

4

У вас есть пара проблем:

  • %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 ! , Этого можно избежать с помощью дополнительного 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
)
0

далее к ответу Дэйвбенхема

выполнение echo% var% внутри блока, такого как FOR или IF, работает некорректно. Переменные% 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 даже для экспертов (возможно, потому что другие вещи могут интерпретироваться по-разному), так что я просто использую это, чтобы показать Вы, что вы можете попробовать!вар! обозначения в 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%. Так что это может быть причиной того, что люди не просто включают режим на полный рабочий день, могут быть и другие причины.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .