Может ли кто-нибудь привести пример того, как пакетный сценарий будет действовать по-разному с отложенным расширением или без него? Есть ли ситуации, когда вы НЕ хотели бы использовать отложенное расширение? Спасибо.
Пример отложенного расширения в пакетном файле
Ответы (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
и расширяете переменную, используя !
вместо %
, переменная каждый раз повторно расширяется, и все работает как положено.
set /A COUNT=COUNT + 1
или более короткое set /A COUNT+=1
, чтобы продемонстрировать, что в арифметическом выражении на переменные можно ссылаться только по их именам. Арифметическое выражение – это строка после set /A
. Справка, выводимая при запуске в окне командной строки set /?
, объясняет отложенное раскрытие в примере IF и FOR, а также анализ специальных переменных в арифметических выражениях.
- person Mofi; 08.09.2017
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».
Ответ Макса дает пример того, как пакетный скрипт будет действовать по-разному с отложенным расширением или без него.
Для полноты картины давайте ответим на другую часть вопроса и покажем ситуацию, когда вы НЕ хотели бы использовать отложенное раскрытие, когда ваши данные содержат восклицательный знак !
(и покажем два способа обработки таких данных ):
@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 thecmd
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!
==>
Как указано в ответе, основное использование отложенного расширения - это настройка и доступ к переменным в контексте скобок.
Хотя это может быть полезно и в других ситуациях.
Параметризация подстроки и замена строки:
@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 используются в качестве параметров.