aGerman wrote: ↑05 Aug 2018 04:56
@Dave I understood the double expansion. Escaping the line feed would be sufficient in that case as you pointed out. As to jeb's original \n variable I still try to understand what it means in terms of the resulting characters. Does the additional SET command lead to triple expansion and the result after the macro expansion is still a single line feed? I'm aware of the addidional escaping, that's not what I'm talking about.
No, I'm pretty sure the macro code only gets parsed twice - Once for the definition, and once for the expansion/execution.
dbenham wrote: ↑04 Aug 2018 09:39
I'm thinking this simpler syntax could be used for macro definition as well, though I would probably use \n for the variable name instead of ;
dbenham wrote: ↑04 Aug 2018 12:22
I'm finally at a PC, and no, it does not work for macros.
This
Code: Select all
(set \n=^
%= This defines an escaped line feed - DO NOT ALTER =%
)
echo Hello%\n%
world!
Is just a more pleasing way of writing
Both the above only get parsed once. The same is true with the IN() clause in earlier posts. But the macro must be parsed twice, once to define the macro, and again to execute the macro. So the more complicated definition is required to define a macro.
I didn't test properly - The simplified \n definition does work for macros after all
My first error in testing was the result of forgetting that the line feeds within a macro definition only work if they are within parentheses, even though I describe the behavior of <LF> parsing fairly well in Phase 2 (partly at the top, and partly later on regarding parentheses processing).
The other mistake is not realizing that both \n = ^<LF><LF>^ and \n = ^<LF> produce the exact same macro definition

They both result in a single <LF> being inserted into the definition, though the path to that result varies a bit.
The original complex definition has ^<LF><LF>^<CR><LF> at the end of the line. The <CR> is stripped in Phase 1.5. Then in Phase 2 the ^<LF><LF> is converted to an escaped <LF> that is not stripped. Then the ^<LF> is stripped, and the next line is read and appended, with the first character of of that line escaped.
The simpler definition has ^<LF><CR><LF> at the end of the line. The <CR> is stripped in Phase 1.5, and then in Phase 2 the ^<LF><LF> is converted to an escaped <LF> that is not stripped, and the next line is simply appended.
Since batch macros with arguments always have an outer FOR statement, all the <LF> are within parentheses, so everything works.
Here is a test script that demonstrates that both \n forms give the same result, and parentheses are needed for the macro to work. The script uses
hexdump.bat to examine the byte values within the variable values.
Code: Select all
@echo off
setlocal enableDelayedExpansion
(set LF=^
%= This defines a Line Feed - DO NO ALTER =%
)
(set \n=^^^%LF%%LF%^%LF%%LF%^^)
call :test ^^^^LFLF^^^^
(set \n=^^^
%= This defines an escaped Line Feed - DO NOT ALTER =%
)
call :test ^^^^LF
exit /b
:test
echo(
echo ======== %1 ========
set test=echo Hello%\n%
echo World
set \n
echo(
>test.txt <nul set /p =!\n!
call hexdump test.txt
echo(
set test
echo(
>test.txt <nul set /p =!test!
call hexdump test.txt
echo(
echo -------- %%test%% --------
%test%
echo(
echo -------- (%%test%%) --------
for /f %%A in (".") do (%test%)
exit /b
--OUTPUT--
Code: Select all
======== ^LFLF^ ========
\n=^
^
5E 0A 0A 5E
test=echo Hello
echo World
65 63 68 6F 20 48 65 6C 6C 6F 0A 65 63 68 6F 20
57 6F 72 6C 64
-------- %test% --------
Hello
-------- (%test%) --------
Hello
World
======== ^LF ========
\n=^
5E 0A
test=echo Hello
echo World
65 63 68 6F 20 48 65 6C 6C 6F 0A 65 63 68 6F 20
57 6F 72 6C 64
-------- %test% --------
Hello
-------- (%test%) --------
Hello
World
Dave Benham