Замена строк в пакете Windows

Замена строк в пакете 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

Но это не так (пример каталога «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в последней строке. У меня действительно нет идей, может кто-нибудь указать мне правильное направление?

ВВ

решение1

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

  • %var%Расширение происходит, когда оператор разбирается, и весь заключенный в скобки блок кода разбирается за один проход, до выполнения любых команд. Таким образом, значение — это значение, которое существовало до начала цикла. Решение — отложенное расширение, которое происходит по мере выполнения каждой команды в цикле.

  • Ваша логика неверна - назначение _newp должно основываться на значении _srcp

Процессор CMD — сложный зверь(и также плохо документировано). Есть несколько точек, где различные типы переменных расширяются, и вы должны полностью понимать их, если вы действительно хотите извлечь максимум пользы из пакетного программирования. Все это объясняется по ссылке, но вкратце порядок расширения следующий:

1) % расширения - Параметр:echo %1 илиПеременная окружения: echo %var%
---- Большая часть анализа уже завершена ----
2) Расширение переменной FOR: 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
)

решение2

в дополнение к ответу davebenham

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

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%. Так что это может быть причиной, по которой люди просто не включают режим на постоянной основе, могут быть и другие причины.

Связанный контент