First of all, delayed expansion does not affect the immediately expanded new-lines (or correctly spoken, line-feed characters), because you are using immediate (%
-)expansion for them.
The major issue is that %
-expansion happens so early, which seems to interfere with recognition of line-breaks when a variable contains such.
Everything behind a line-break becomes dismissed every time the parser expands a %
-variable containing line-breaks, so they must be escaped, leading to manifold escaping sequences. This can be demonstrated by the following script:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem // Define a line-feed character:
set \n=^
rem // Define an escaped line-feed character:
set NL=^^^%\n%%\n%^%\n%%\n%
::rem // Redefine the escaped new-line character; it does not change, because the parser first expands `%`-variables before it recognises line-breaks in them:
::set NL=^^%NL%%NL%
rem // Define multi-escaped sequences needed when the same expanded value passes through the parser several times:
set NLNL=^^^^^^^^^^^^^^%NL%%NL%^^%NL%%NL%^^^^^^%NL%%NL%^^%NL%%NL%
set NLNLNL=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%NL%%NL%^^%NL%%NL%^^^^^^%NL%%NL%^^%NL%%NL%^^^^^^^^^^^^^^%NL%%NL%^^%NL%%NL%^^^^^^%NL%%NL%^^%NL%%NL%
::set NLNLNL=^^^^^^^^^^^^^^^^^^^^^^^^%NLNL%%NLNL%^^^^^^^^%NLNL%%NLNL%
echo ---- DEFINITION ----
set NL
echo --------------------
echo !\n! ***** IMMEDIATE EXPANSION ***** !\n!
rem // The more parser passes the more escaping is needed:
echo -- VARIABLE CHECK --
set errMsg=This would be the first custom error message%NLNLNL%
set errMsg
set errMsg=%errMsg%This would be the second custom error message%NLNL%
set errMsg
set errMsg=%errMsg%This would be the third custom error message%NL%
set errMsg
echo -- MESSAGE OUTPUT --
echo %errMsg%
echo --------------------
echo !\n! ***** `CALL` EXPANSION ***** !\n!
echo -- VARIABLE CHECK --
set errMsg=This would be the first custom error message%%NL%%
set errMsg
set errMsg=%errMsg%This would be the second custom error message%%NL%%
set errMsg
set errMsg=%errMsg%This would be the third custom error message%%NL%%
set errMsg
echo -- MESSAGE OUTPUT --
call echo %errMsg%
echo --------------------
echo !\n! ***** DELAYED EXPANSION ***** !\n!
echo -- VARIABLE CHECK --
set errMsg=This would be the first custom error message!\n!
set errMsg
set errMsg=!errMsg!This would be the second custom error message!\n!
set errMsg
set errMsg=!errMsg!This would be the third custom error message!\n!
set errMsg
echo -- MESSAGE OUTPUT --
echo !errMsg!
echo --------------------
endlocal
exit /B
This is the related Command Prompt output:
---- DEFINITION ----
NL=^
NLNL=^^^^^^^
^
^^^
^
NLNLNL=^^^^^^^^^^^^^^^
^
^^^
^
^^^^^^^
^
^^^
^
--------------------
***** IMMEDIATE EXPANSION *****
-- VARIABLE CHECK --
errMsg=This would be the first custom error message^^^^^^^
^
^^^
^
errMsg=This would be the first custom error message^^^
^
This would be the second custom error message^^^
^
errMsg=This would be the first custom error message^
This would be the second custom error message^
This would be the third custom error message
-- MESSAGE OUTPUT --
This would be the first custom error message
This would be the second custom error message
This would be the third custom error message
--------------------
***** `CALL` EXPANSION *****
-- VARIABLE CHECK --
errMsg=This would be the first custom error message%NL%
errMsg=This would be the first custom error message%NL%This would be the second custom error message%NL%
errMsg=This would be the first custom error message%NL%This would be the second custom error message%NL%This would be the third custom error message%NL%
-- MESSAGE OUTPUT --
This would be the first custom error message
This would be the second custom error message
This would be the third custom error message
--------------------
***** DELAYED EXPANSION *****
-- VARIABLE CHECK --
errMsg=This would be the first custom error message
errMsg=This would be the first custom error message
This would be the second custom error message
errMsg=This would be the first custom error message
This would be the second custom error message
This would be the third custom error message
-- MESSAGE OUTPUT --
This would be the first custom error message
This would be the second custom error message
This would be the third custom error message
--------------------
In the IMMEDIATE EXPANSION
section complicated escape sequences are required to maintain the line-breaks when command lines pass through the parsing process multiple times.
The CALL
EXPANSION
section illustrates a simpler way, using the call
command, which introduces another parsing phase, which lets the literal string portion %NL%
be expanded, which is actually contained in the errMsg
variable rather than line-breaks. Note that call
is slow and has got side-effects, like caret-(^
-)doubling and loss of &
, |
, <
and >
under certain circumstances.
The best option is certainly to use delayed expansion as shown through the DELAYED EXPANSION
section, because this allows the variable errMsg
to actually contain the line-breaks and to safely expand them without being recognised by the parser too early.