Reputation: 1036
In order to store multiple lines inside a variable from a text file, I am using the answer from this question: https://stackoverflow.com/a/10624240/1513458
Using this script inline and parsing large files gave me a maximum setlocal error. So to counter this, I put the script in a subroutine, and called it from the line(s) i needed it in.
An echo at the bottom of the subroutine before it terminates would output the expected result fine... but back at the top where it was originally called, the variable is empty. Why is that?
Here's a shortened version of the script:
setlocal EnableDelayedExpansion
set sourcefile=cc1
call :readfile %sourcefile%
echo !insert!
goto :EOF
:readfile
SETLOCAL DisableDelayedExpansion
set "insert="
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ %SOURCELOC%\%1.txt"`) do (
set "line=%%a"
SETLOCAL EnableDelayedExpansion
set "line=!line:#=#S!"
set "line=!line:*:=!"
for /F "delims=" %%p in ("!insert!#L!line!") do (
ENDLOCAL
set "insert=%%p"
)
)
SETLOCAL EnableDelayedExpansion
if defined insert (
set "insert=!insert:~2!"
set ^"insert=!insert:#L=^
!"
set "insert=!insert:#S=#!"
)
rem A echo !insert! here would output the expected result
goto :EOF
Thanks so much for all your help. Batch is clearly not meant for me, but i need to tough this one through.
Upvotes: 1
Views: 395
Reputation: 130819
Your :readfile routine has SETLOCAL at the top that localizes environment changes. When a routine ends, there is an implicit ENDLOCAL executed for every active SETLOCAL that was instantiated within the routine. So the environment is restored to the state that existed prior to the call.
There is no need for a called subroutine. Your earlier code must have had SETLOCAL without an ENDLOCAL within the FOR loop. That would cause the max SETLOCAL error. Now your FOR loop has paired SETLOCAL/ENDLOCAL, so no more problem.
It is possible to transport any value accross the ENDLOCAL barrier, but it uses an advanced technique.
Some simple restructuring avoids the need to do that. But be careful - no batch variable can contain more than 8192 characters.
setlocal disableDelayedExpansion
set sourcefile=cc1
set "insert="
for /f "delims=" %%a in ('findstr /n "^" "%SOURCELOC%\%~1.txt"') do (
set "line=%%a"
setlocal EnableDelayedExpansion
set "line=!line:#=#S!"
set "line=!line:*:=!"
for /f "delims=" %%p in ("!insert!#L!line!") do (
endlocal
set "insert=%%p"
)
)
setlocal EnableDelayedExpansion
if defined insert (
set "insert=!insert:~2!"
set ^"insert=!insert:#L=^
!"
set "insert=!insert:#S=#!"
)
echo !insert!
EDIT
Here is a solution that demonstrates returning any value across the ENDLOCAL border (except it does not support carriage return. There is a simple extension that supports carriage return). The routine will give the correct result, regardless whether it was called with delayed expansion enabled or disabled. The technique was developed by DosTips user jeb here:http://www.dostips.com/forum/viewtopic.php?f=3&t=1839, and here: http://www.dostips.com/forum/viewtopic.php?p=6930#p6930. There you will find some explanation as to how it works, but it is not for the faint of heart.
@echo off
setlocal enableDelayedExpansion
set sourceloc=.
set sourcefile=test
set ^"LF=^
^"
call :readFile "%sourcefile%"
echo(!insert!
exit /b
:readFile
setlocal
set "notDelayed=!"
setlocal disableDelayedExpansion
set "insert="
for /f "delims=" %%a in ('findstr /n "^" "%SOURCELOC%\%~1.txt"') do (
set "line=%%a"
setlocal EnableDelayedExpansion
set "line=!line:%%=%%J!"
set "line=!line:*:=!"
for /f "delims=" %%p in ("!insert!%%~L!line!") do (
endlocal
set "insert=%%p"
)
)
setlocal enableDelayedExpansion
if defined insert (
set "insert=!insert:"=%%~K!"
if not defined notDelayed set "insert=!insert:^=^^^^!"
)
if defined insert if not defined notDelayed set "insert=%insert:!=^^^!%" Do not remove!
set "replace=%% """"
for %%L in ("!LF!") do for /f "tokens=1,2" %%J in ("!replace!") do (
endlocal
endlocal
endlocal
set "insert=%insert%" Do not remove!
)
exit /b
Upvotes: 3
Reputation: 37569
try this:
setlocal EnableDelayedExpansion
set sourcefile=cc1
call :readfile insert
echo %insert%
goto :EOF
:readfile
SETLOCAL DisableDelayedExpansion
set "insert="
FOR /F "delims=" %%a in ('findstr /n "^" "%SOURCELOC%\%1.txt"') do (
set "line=%%a"
SETLOCAL EnableDelayedExpansion
set "line=!line:#=#S!"
set "line=!line:*:=!"
for /F "delims=" %%p in ("!insert!#L!line!") do (
ENDLOCAL
set "insert=%%p"
)
)
SETLOCAL EnableDelayedExpansion
if defined insert (
set "insert=!insert:~2!"
set ^"insert=!insert:#L=^
!"
set "insert=!insert:#S=#!"
)
rem A echo !insert! here would output the expected result
SET "%1=!insert!"
ENDLOCAL
goto :EOF
Upvotes: 0