As derived from this thread, you cannot echo a multi-line string using immediate (%
-)expansion, because everything after the first line-break is ignored.
To make your script working you need to correct two issues:
- before the line
endlocal & set data=%out%
you must replace every new-line in variable out
by an escaped new-line, that is the sequence ^
plus new-line plus new-line, which is exactly the same that you are using for defining the variable NL
;
echo %data%
truncates the displayed string at the first occurrence of a new-line in the value of variable data
, so you need to use set data
to show the actual content of the variable (or more precisely said, of all variables whose names begin with data
);
Both of these items are commented (rem
) in the following code:
@echo off
setlocal EnableDelayedExpansion
set out=
set NL=^
for /F "delims= eol=|" %%i in ('dir /b') do (
if defined out set "out=!out!!NL!"
set "out=!out!%%i"
)
echo * Original variable content:
set out
rem // Replace every new-line by an escaped new-line:
set out=!out:^%NL%%NL%=^^^%NL%%NL%^%NL%%NL%!
echo * Modified variable content:
set out
endlocal & set data=%out%
rem // Do not use `echo` to show true content of variable:
echo * Returned variable content:
set data
echo * Mistaken variable content:
echo %data%
exit /B 0
Although the variable value is now correctly passed over the endlocal
barrier, this approach is not exactly brilliant, because it does not allow you to use variable %data%
(again because everything after the first line-break is ignored as initially mentioned), unless you have got delayed expansion enabled in the hosting cmd
instance, which would permit to use !data!
.
Another remaining problem is that special characters in the multi-line string (like ^
, &
, (
, )
and "
, <
, >
, |
) may cause syntax errors or other unexpected issues. However, this can be avoided by using a for
meta-variable rather than a normal environment variable for passing the variable value beyond the endlocal
barrier, because the former are expanded after special character recognition, in contrast to the latter, which are expanded before:
@echo off
setlocal EnableDelayedExpansion
set out=
set NL=^
for /F "delims=" %%i in ('dir /b') do (
if defined out set "out=!out!!NL!"
set "out=!out!%%i"
)
echo # Original variable content:
set out
rem /* Use a `for` meta-variable rather than a normal environment variable to
rem pass the variable value beyond the `endlocal` barrier;
rem a standard `for` loop can be used here, because there are not going to be
rem wildcards `?` and `*` in the variable value since they have already been
rem resolved by `dir`; `for /F` cannot be used here due to the new-lines: */
for %%j in ("!out!") do endlocal & set "data=%%~j"
rem // Do not use `echo` to show true content of variable:
echo # Returned variable content:
set data
echo # Mistaken variable content:
echo %data%
exit /B 0
The problem not being able to use variable %data%
remains though.
To be able to use variable %data%
with immediate expansion you could however simply store escaped new-lines rather than literal ones in the variable, because upon expansion you will have the intended literal new-line:
@echo off
setlocal EnableDelayedExpansion
set out=
set NL=^
for /F "delims=" %%i in ('dir /b') do (
if defined out set "out=!out!!NL!"
set "out=!out!%%i"
)
echo # Original variable content:
set out
rem // Replace every new-line by an escaped new-line:
set out=!out:^%NL%%NL%=^^^%NL%%NL%^%NL%%NL%!
echo # Modified variable content:
set out
rem /* Use a `for` meta-variable rather than a normal environment variable to
rem pass the variable value beyond the `endlocal` barrier;
rem a standard `for` loop can be used here, because there are not going to be
rem wildcards `?` and `*` in the variable value since they have already been
rem resolved by `dir`; `for /F` cannot be used here due to the new-lines: */
for %%j in ("!out!") do endlocal & set "data=%%~j"
rem // Do not use `echo` to show true content of variable:
echo # Actual variable content:
set data
echo # Parsed variable content:
echo %data%
exit /B 0
But regard that this is only going to work when %data%
does not appear within quoted (""
) strings.