mcu
mcu

Reputation: 3512

Batch: Concatenate two arbitrary strings outside SETLOCAL EnableDelayedExpansion

I need to concatenate two string variables and place the result back in the first variable. These two strings can contain any arbitrary characters, like newline, exclamation, etc.

The main script runs with delayed expansion disabled, so I have to use SETLOCAL EnableDelayedExpansion for actual concatenation. I just don't know how to get the result back out of the local and into the global variable.

I would like to avoid using temporary files.

I wish batch files allowed delayed expansion outside of the local block.

Thanks.

EDIT :

@Jeb
I tried using your code inline, instead of in a function, and it worked.
Then I tried putting it in a FOR loop, and that broke it.
Function call from a loop = works.
Inline is a loop = didn't work for me.
I don't need that functionality right now. This is just an observation.
Thanks.

@echo off
REM Changed from function call to inline implementation
setlocal EnableDelayedExpansion
cls
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
set LF=^


rem TWO Empty lines are neccessary
set "original=zero*? %%~A%%~B%%~C%%~L!LF!one&line!LF!two with exclam^! !LF!three with "quotes^&"&"!LF!four with ^^^^ ^| ^< ^> ( ) ^& ^^^! ^"!LF!xxxxxwith CR!CR!five !LF!six with ^"^"Q ^"^"L still six "

setlocal DisableDelayedExpansion
SET result=""
REM call :lfTest result original
::::::::::::::::::::
for /L %%i in (1,1,2) do (
setlocal
set "NotDelayedFlag=!"
echo(
if defined NotDelayedFlag (echo lfTest was called with Delayed Expansion DISABLED) else echo lfTest was called with Delayed Expansion ENABLED
setlocal EnableDelayedExpansion
set "var=!original!"

rem echo the input is:
rem echo !var!
echo(

rem ** Prepare for return
set "var=!var:%%=%%~2!"
set "var=!var:"=%%~3!"
for %%a in ("!LF!") do set "var=!var:%%~a=%%~L!"
for %%a in ("!CR!") do set "var=!var:%%~a=%%~4!"

rem ** It is neccessary to use two IF's, else the %var% expansion doesn't work as expected
if not defined NotDelayedFlag set "var=!var:^=^^^^!"
if not defined NotDelayedFlag set "var=%var:!=^^^!%" !

set "replace=%% """ !CR!!CR!"
for %%L in ("!LF!") do (
   for /F "tokens=1,2,3" %%2 in ("!replace!") DO (
     ENDLOCAL
     ENDLOCAL
     set "result=%var%" !
     @echo off
   )
)
)
::::::::::::::::::::
setlocal EnableDelayedExpansion
echo The result with disabled delayed expansion is:
if !original! == !result! (echo OK) ELSE echo !result!

echo ------------------
echo !original!

pause
goto :eof

Upvotes: 3

Views: 2766

Answers (1)

jeb
jeb

Reputation: 82307

Like I said in your other question: Batch: Returning a value from a SETLOCAL EnableDelayedExpansion

Just follow the link for a "perfect" solution

Or I can paste the code here

rem ** Preparing CR and LF for later use
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
set LF=^


rem TWO Empty lines are neccessary

Then at the start of your function, to detect if delayedExpansion is OFF or ON

setlocal
set "NotDelayedFlag=!"
setlocal EnableDelayedExpansion

And at the end of your function, to return the value

rem ** Prepare for return
set "var=!var:%%=%%~2!"
set "var=!var:"=%%~3!"
for %%a in ("!LF!") do set "var=!var:%%~a=%%~L!"
for %%a in ("!CR!") do set "var=!var:%%~a=%%~4!"

rem ** It is neccessary to use two IF's, else the %var% expansion doesn't work as expected
if not defined NotDelayedFlag set "var=!var:^=^^^^!"
if not defined NotDelayedFlag set "var=%var:!=^^^!%" !

set "replace=%% """ !CR!!CR!"
for %%L in ("!LF!") do (
   for /F "tokens=1,2,3" %%2 in ("!replace!") DO (
     ENDLOCAL
     ENDLOCAL
     set "%~1=%var%" !
     @echo off
      goto :eof
   )
)

EDIT: A little bit shorter variation
Ok, this looks a little bit complicated, and in many cases it can be solved with an other trick.
If you know, that you will switch back from an EnableDelayed to DisableDelayed and you are sure not using any LF a FOR-RETURN will work too.

@echo off
setlocal
call :myTest result
set result
goto :eof

:myTest
setlocal EnableDelayedExpansion
rem ... do something here
set "value=^!_&_%%_|_>"

echo --
for /f ^"eol^=^

^ delims^=^" %%a in ("!value!") do (
    endlocal
    set "%~1=%%a"
    goto :eof
) 

The splitting of the for /f ^"eol^=^.... is only for disabling the eol character.

Upvotes: 2

Related Questions