Пример отложенного расширения в пакетном файле

Может ли кто-нибудь привести пример того, как пакетный сценарий будет действовать по-разному с отложенным расширением или без него? Есть ли ситуации, когда вы НЕ хотели бы использовать отложенное расширение? Спасибо.


person Neil Weicher    schedule 11.05.2012    source источник


Ответы (4)


Посмотрите на следующие примеры...

Пример 1. В следующем коде НЕ используется отложенное расширение, поэтому переменные в цикле for раскрываются только один раз. Это означает, что %Count% всегда будет расширяться до 0 на каждой итерации цикла, независимо от того, что мы делаем с ним с помощью команды set:

@echo off
set COUNT=0

for %%v in (1 2 3 4) do (
  set /A COUNT=%COUNT% + 1
  echo Count = %COUNT%
)
pause

Итак, этот скрипт выведет:

Count = 0
Count = 0
Count = 0
Count = 0

Это не то, как этот цикл должен работать.

Пример 2: С другой стороны, если мы используем отложенное расширение, у нас есть следующий сценарий, который будет работать, как и ожидалось.

setlocal ENABLEDELAYEDEXPANSION
set COUNT=0

for %%v in (1 2 3 4) do (
  set /A COUNT=!COUNT! + 1
  echo Count = !COUNT!
)

pause

и, как и ожидалось, он выведет:

Count = 1
Count = 2
Count = 3
Count = 4

Когда вы используете ENABLEDELAYEDEXPANSION и расширяете переменную, используя ! вместо %, переменная каждый раз повторно расширяется, и все работает как положено.

person Max    schedule 11.05.2012
comment
Хорошие примеры. Но еще лучше было бы использовать set /A COUNT=COUNT + 1 или более короткое set /A COUNT+=1, чтобы продемонстрировать, что в арифметическом выражении на переменные можно ссылаться только по их именам. Арифметическое выражение – это строка после set /A. Справка, выводимая при запуске в окне командной строки set /?, объясняет отложенное раскрытие в примере IF и FOR, а также анализ специальных переменных в арифметических выражениях. - person Mofi; 08.09.2017
comment
Стоит уточнить, что раскрытие происходит при разборе строки, а в случае блоков, разделенных скобками (например, if блоков), весь блок считается за строку (источник). - person OfirD; 08.04.2020

Я хотел добавить отличный пример того, как «EnableDelayedExpansion» (EDE) может быть полезен помимо вездесущих примеров цикла FOR.

Вот строка данных о землетрясениях, которую я хочу проанализировать (я называю ее 1line.txt).

ak_11574812 2015.04.29.193822 62,9525 -148,8849 1,0 9,5 1 49 км к югу от Кантуэлла, Аляска

Проблема, с которой я столкнулся, заключалась в том, что последний сегмент этой строки не всегда начинается с одного и того же номера столбца. Поэтому мне нужно было создать гибкую команду SET, которая точно выдернет последний сегмент этой строки.

ECHO OFF
setlocal enableDelayedExpansion
set where=72
set /p line=<1line.txt
set locate=!line:~%where%,28!
echo %locate%

EDE позволяет мне поместить переменную (где) внутри другой переменной (строки). EDE сначала переведет переменную, заключенную в скобки %, а затем обработает переменную, заключенную в скобки ! и (в этом случае) вытолкнуть результаты в переменную «locate».

person Bruce Sinkula    schedule 30.04.2015

Ответ Макса дает пример того, как пакетный скрипт будет действовать по-разному с отложенным расширением или без него.

Для полноты картины давайте ответим на другую часть вопроса и покажем ситуацию, когда вы НЕ хотели бы использовать отложенное раскрытие, когда ваши данные содержат восклицательный знак ! (и покажем два способа обработки таких данных ):

@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion

  set "_auxFile=%temp%\%~n0.txt"
  rem create multiline sample file
  >"%_auxFile%" ( for /L %%G in (1,1,3) do echo line %%G is 100%% valid! Sure! Hurrah!)
  rem create one-line sample file
  >"%_auxFile%" echo this line is 100%% valid! Sure! Hurrah!

  echo(
  echo --- file content 
  type "%_auxFile%"

  echo(
  SETLOCAL EnableDelayedExpansion
    echo --- enabled delayed expansion chokes down unescaped exclamation marks^^^! "^!"
    for /F "usebackq delims=" %%G in ("%_auxFile%") do (
      set "_auxLine=%%~G"
      echo loop var=%%~G
      echo _auxLine=!_auxLine!
    )
  ENDLOCAL
  echo(
  SETLOCAL DisableDelayedExpansion
    echo --- toggled delayed expansion works although might be laborious!
    for /F "usebackq delims=" %%G in ("%_auxFile%") do (
      set "_auxLine=%%G"
      echo loop var=%%G
      SETLOCAL EnableDelayedExpansion
        echo _auxLine=!_auxLine!
      ENDLOCAL
    )
  ENDLOCAL
  echo(
  SETLOCAL DisableDelayedExpansion
    echo --- keep delayed expansion DISABLED: use CALL command!
    for /F "usebackq delims=" %%G in ("%_auxFile%") do (
      set "_auxLine=%%G"
      echo loop var=%%G
      call :ProcessVar
    )
  ENDLOCAL

  rem delete the sample file
  del "%_auxFile%"
ENDLOCAL
goto :eof

:ProcessVar
  echo _auxLine=%_auxLine%
  echo WARNING: neither !_auxLine! nor %%G loop variable is available here!  
goto :eof

Обратите внимание, что приведенный выше скрипт показывает правильные способы выхода

  • % подписать процент, %% удвоив его (отложенное расширение не имеет значения), и
  • ! exclamation mark if delayed expansion is enabled:
    • "^!" if enclosed in a pair of double quotes, then use the cmd and batch-script general escape character ^ caret;
    • ^^^! в противном случае используйте три каретки ^.

Вывод:

==> D:\bat\SO\10558316.bat

--- file content
this line is 100% valid! Sure! Hurrah!

--- enabled delayed expansion chokes down unescaped exclamation marks! "!"
loop var=this line is 100% valid Hurrah
_auxLine=this line is 100% valid Hurrah

--- toggled delayed expansion works although might be laborious!
loop var=this line is 100% valid! Sure! Hurrah!
_auxLine=this line is 100% valid! Sure! Hurrah!

--- keep delayed expansion DISABLED: use CALL command!
loop var=this line is 100% valid! Sure! Hurrah!
_auxLine=this line is 100% valid! Sure! Hurrah!
WARNING: !_auxLine! as well as %G loop variables are not available here!

==>
person JosefZ    schedule 25.06.2016

Как указано в ответе, основное использование отложенного расширения - это настройка и доступ к переменным в контексте скобок.

Хотя это может быть полезно и в других ситуациях.

Параметризация подстроки и замена строки:

@echo off
setlocal enableDelayedExpansion

set "string=test string value"
set start=5
set get_next=6

echo #!string:~%start%,%get_next%!#

set "search_for=string"
set "replace_with=text"

echo #!string:%search_for%=%replace_with%!#

вывод будет:

#string#
#test text value#

хотя это может быть достигнуто с помощью дополнительного вызова, этот способ более эффективен

Использование команды shift в скобках с параметризованным доступом к аргументу

@echo off

echo first attempt:
(
    echo "%~1"
    shift
    echo "%~1"
)
::now the shift command will take effect

setlocal enableDelayedExpansion
echo second attempt:

(   
    set /a argument=1
    call echo %%!argument! 
    shift
    call echo %%!argument! 
)

вывод будет:

first attempt:
"first argument"
"first argument"
second attempt:
"second argument"
"third argument"

Как видите, доступ к параметризованным аргументам можно осуществить только с отложенным расширением.

Использование for tokens (или аргументов функции) для параметризации

Еще один подход для смешивания !s и %s, который может быть полезен для вложенных циклов:

@echo off
setlocal enabledelayedexpansion
set begin=2
set end=2
set string=12345

for /f "tokens=1,2" %%A in ("!begin! !end!") do set "string2=!string:~%%A,%%B!"
echo !string2!

endlocal

как вы можете видеть, теперь токены команды for используются в качестве параметров.

person npocmaka    schedule 26.01.2021