Как работают SETLOCAL и ENABLEDELAYEDEXPANSION? - PullRequest
42 голосов
/ 13 июля 2011

Я заметил, что в большинстве сценариев они обычно находятся в одной и той же строке:

SETLOCAL ENABLEDELAYEDEXPANSION

Являются ли эти две команды на самом деле отдельными и могут быть записаны в отдельных строках?

Будет ли настройка ENABLEDELAYEDEXPANSION оказывать неблагоприятное влияние на сценарий, если она задана в первых строках сценария и не отключена до конца сценария?

Ответы [ 4 ]

94 голосов
/ 27 августа 2013

Я думаю, вы должны понимать, что такое задержанное расширение . Существующие ответы не объясняют это (достаточно) ИМХО.

Ввод SET /? достаточно хорошо объясняет:

Задержка расширения переменной среды полезна для обхода ограничения текущего расширения, которое происходит, когда линия текст читается, а не когда он выполняется. Следующий пример демонстрирует проблему с немедленным расширением переменной:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "%VAR%" == "after" @echo If you see this, it worked
)

никогда не будет отображать сообщение, так как% VAR% в операторах ОБА 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%

Другим примером является этот командный файл:

@echo off
setlocal enabledelayedexpansion
set b=z1
for %%a in (x1 y1) do (
 set b=%%a
 echo !b:1=2!
)

Это печатает x2 и y2: каждый 1 заменяется на 2.

Без setlocal enabledelayedexpansion восклицательные знаки - только это, поэтому он будет повторять !b:1=2! дважды.

Поскольку нормальные переменные среды раскрываются, когда оператор (block) равен read , при расширении %b:1=2% используется значение, b перед циклом: z2 (но y2, если не задано ).

20 голосов
/ 13 июля 2011

ENABLEDELAYEDEXPANSION - это параметр, передаваемый команде SETLOCAL (см. setlocal /?)

Его действие действует в течение всего сценария или ENDLOCAL:

Когда достигается конец пакетного сценария, подразумевается ENDLOCAL для любых ожидающих SETLOCAL команд, выданных этим пакетным сценарием.

В частности, это означает, что есливы используете SETLOCAL ENABLEDELAYEDEXPANSION в скрипте, любые изменения переменных среды теряются в конце его , если вы не примете специальные меры .

9 голосов
/ 22 июля 2011

Часть ENABLEDELAYEDEXPANSION ТРЕБУЕТСЯ в некоторых программах, которые используют отложенное расширение, то есть принимает значения переменных, которые были изменены внутри команд IF или FOR, заключая их имена в восклицательные знаки.

Если вывключите это расширение в сценарии, который не требует его, сценарий ведет себя иначе, только если он содержит имена, заключенные в восклицательные знаки! LIKE!!ЭТИ!.Обычно имя просто стирается, но если переменная с тем же именем существует случайно, то результат непредсказуем и зависит от значения такой переменной и места, где она появляется.

Требуется часть SETLOCALтолько в нескольких специализированных (рекурсивных) программах, но обычно используется, когда вы хотите убедиться, что случайно не изменили любую существующую переменную с тем же именем, или если вы хотите автоматически удалить все переменные, используемые в вашей программе.Однако, поскольку нет отдельной команды для включения отложенного расширения, программы, которые требуют этого, также должны включать часть SETLOCAL.

0 голосов
/ 30 января 2014

Реальная проблема часто существует, потому что любые переменные, установленные внутри, не будут экспортированы, когда этот пакетный файл завершится. Поэтому его невозможно экспортировать, что вызвало у нас проблемы. В результате я просто установил в реестре ВСЕГДА используемое расширение с задержкой (я не знаю, почему это не по умолчанию, это может быть проблема скорости или устаревшей совместимости.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...