Сохранение восклицательных знаков в переменной между пакетами setlocals
Попытка сохранить восклицательные знаки в переменных. Упрощенный, иллюстративный скрипт ниже:
echo off
set testvar="C:\Windows\TestOfIllegals[!]"
echo Pre-EnableDE: %testvar%
setlocal enableextensions enabledelayedexpansion
echo Post-EnableDE: %testvar%
Setlocal DisableDelayedExpansion
echo ssetlocal sub-instance...
echo TestVar after re-disableDE: %testvar%
set modTestVar=%testvar%
echo TestVar to new var, modTestVar: %modTestVar%
endlocal & set "RetVar2=%modTestVar%"
echo modTestVar back in main script: %RetVar2%
Setlocal DisableDelayedExpansion
echo modTestVar, main script in another setlocal diasbleDE instance: %RetVar2%
endlocal
pause
exit /b
это производит вывод:
Pre-EnableDE: "C:\Windows\TestOfIllegals[!]"
Post-EnableDE: "C:\Windows\TestOfIllegals[]"
ssetlocal sub-instance...
TestVar after re-disableDE: "C:\Windows\TestOfIllegals[!]"
TestVar to new var, modTestVar: "C:\Windows\TestOfIllegals[!]"
modTestVar back in main script: "C:\Windows\TestOfIllegals[]"
modTestVar, main script in another setlocal diasbleDE instance: "C:\Windows\TestOfIllegals[]"
Почему восклицательный знак не сохраняется в modTestVar? Есть какой-либо способ сделать это?
(Я знаю, что люди говорили, прежде чем "опубликовать полный сценарий" - но довольно долго, и это представляет основную проблему. Тем не менее, рад опубликовать, если полезно).
Спасибо
1 ответ
Он сохраняется в переменной, но вам нужно использовать отложенное расширение.
Когда вы использовали процентное расширение в режиме отложенного расширения, переменная будет расширена, и содержимое, особенно восклицательные знаки, будет проанализировано и позже, и один восклицательный знак будет просто удален.
echo off
set testvar="C:\Windows\TestOfIllegals[!]"
echo Pre-EnableDE: %testvar%
setlocal enableextensions enabledelayedexpansion
echo Post-EnableDE: !testvar!
Setlocal DisableDelayedExpansion
echo ssetlocal sub-instance...
echo TestVar after re-disableDE: %testvar%
set modTestVar=%testvar%
echo TestVar to new var, modTestVar: %modTestVar%
endlocal & set "RetVar2=%modTestVar%"
echo modTestVar back in main script: !RetVar2!
Setlocal DisableDelayedExpansion
echo modTestVar, main script in another setlocal diasbleDE instance: %RetVar2%
endlocal
pause
Другая / единственная проблема - когда вы пытаетесь передать переменную через эндокальный барьер (например, endlocal & set "RetVar2=%modTestVar%"
).
Это не тривиально.
Это пакетный макрос для этого, используется следующим образом%endlocal% modTestVar
setlocal DisableDelayedExpansion
set LF=^
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
%= I use EDE for EnableDelayeExpansion and DDE for DisableDelayedExpansion =%
set ^"endlocal=for %%# in (1 2) do if %%#==2 (%\n%
setlocal EnableDelayedExpansion%\n%
%= Take all variable names into the varName array =%%\n%
set varName_count=0%\n%
for %%C in (!args!) do set "varName[!varName_count!]=%%~C" ^& set /a varName_count+=1%\n%
%= Build one variable with a list of set statements for each variable delimited by newlines =%%\n%
%= The lists looks like --> set result1=myContent\n"set result1=myContent1"\nset result2=content2\nset result2=content2\n =%%\n%
%= Each result exists two times, the first for the case returning to DDE, the second for EDE =%%\n%
%= The correct line will be detected by the (missing) enclosing quotes =%%\n%
set "retContent=1!LF!"%\n%
for /L %%n in (0 1 !varName_count!) do (%\n%
for /F "delims=" %%C in ("!varName[%%n]!") DO (%\n%
set "content=!%%C!"%\n%
set "retContent=!retContent!"set !varName[%%n]!=!content!"!LF!"%\n%
if defined content (%\n%
%= This complex block is only for replacing '!' with '^!' =%%\n%
%= First replacing '"'->'""q' '^'->'^^' =%%\n%
set ^"content_EDE=!content:"=""q!"%\n%
set "content_EDE=!content_EDE:^=^^!"%\n%
%= Now it's poosible to use CALL SET and replace '!'->'""e!' =%%\n%
call set "content_EDE=%%content_EDE:^!=""e^!%%"%\n%
%= Now it's possible to replace '""e' to '^', this is effectivly '!' -> '^!' =%%\n%
set "content_EDE=!content_EDE:""e=^!"%\n%
%= Now restore the quotes =%%\n%
set ^"content_EDE=!content_EDE:""q="!"%\n%
) ELSE set "content_EDE="%\n%
set "retContent=!retContent!set "!varName[%%n]!=!content_EDE!"!LF!"%\n%
)%\n%
)%\n%
%= Now return all variables from retContent over the barrier =%%\n%
for /F "delims=" %%V in ("!retContent!") DO (%\n%
%= Only the first line can contain a single 1 =%%\n%
if "%%V"=="1" (%\n%
%= We need to call endlocal twice, as there is one more setlocal in the macro itself =%%\n%
endlocal%\n%
endlocal%\n%
) ELSE (%\n%
%= This is true in EDE =%%\n%
if "!"=="" (%\n%
if %%V==%%~V (%\n%
%%V !%\n%
)%\n%
) ELSE IF not %%V==%%~V (%\n%
%%~V%\n%
)%\n%
)%\n%
)%\n%
) else set args="