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

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

5 ответов

Решение

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

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

Я хотел добавить отличный пример того, как "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".

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

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

@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

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

  • % знак процента по %% удвоение (задержка расширения не имеет значения) и
  • ! восклицательный знак, если включено отложенное расширение:
    • "^!" если заключено в двойные кавычки, используйте cmd и общий управляющий символ пакетного сценария ^ каретка;
    • ^^^! в противном случае используйте три ^ CARETS.

Выход:

==> 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!

==>

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

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

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

      @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 это может быть полезно для вложенных циклов:

      @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 используются в качестве параметров.

Несколько ответов здесь отвечают на вопрос «Как использовать отложенное расширение?» вопрос или что произойдет, если вы не используете отложенное расширение. Однако второй вопрос: «Есть ли ситуации, когда вы НЕ хотели бы использовать отложенное расширение?» и пара ответов берет этот вопрос как «как избежать проблем, вызванных использованием отложенного расширения?»

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

Если вы хотите поменять местами содержимое двух переменных, самый простой способ сделать это — использовать расширение переменной %standard%:

      set "var1=%var2%"  &  set "var2=%var1%"

То, как работает расширение %standard%, позволяет выполнить эту замену без использования какой-либо вспомогательной переменной. Насколько я знаю, пакетный файл "язык программирования" - единственный, который позволяет выполнять этот обмен таким образом, то есть эффективно используя языковую "особенность" (не через специализированную инструкцию "обмена"/ утверждение).

Другие вопросы по тегам