0

I'm trying to use a FOR loop to read the lines in a text file, but I also need to keep track of some variables and evaluate them. The easiest way to do that is by enabling DelyaedExpansion. Actually, it seems to be the ONLY way as everything else I've tried in relation to variables fails miserably if I don't use it. Unfortunately, this means that if any of the lines of text in the file contain exclamation points, they will be stripped out.

I thought I had found a solution by reading a line of text and putting it into a variable, THEN enabling DelayedExpansion, doing the variable operations, and finally using ENDLOCAL & SET VARIABLE=%VARIABLE% to preserve the value. Unfortunately that doesn't seem to work if the ENDLOCAL statement is inside a loop.

For example;

echo off
for /F "delims=" %%F in (test.txt) do (
    set Line=%%F
    setlocal enabledelayedexpansion
    set /a Count=Count+1
    echo !Count! - !Line!
    endlocal & set Count=%Count%
)
echo Total: %Count%

Each time the loop repeats, the value of "Count" is reset to zero.

If I move the SETLOCAL command before the FOR command, it will strip any "!" from the text, which is unacceptable.

Please note: The example above is only a small part of a much larger script that does many things with the variables inside the loop. I have boiled the problem down to the bare minimum to make it easy to understand. I need to preserve "!" in text read from a file while also being able to perform multiple variable operations within each loop.

So I either need a way to read text from a file, one line at a time, with DeleyedExpansion enabled AND preserve any "!" in the text, or preserve the value of variables that are defined within the SETLOCAL/ENDLOCAL commands within a loop.

Compo
  • 36,585
  • 5
  • 27
  • 39
  • 1
    Have you looked at the answer to this previous question? https://stackoverflow.com/questions/3262287/make-an-environment-variable-survive-endlocal – Buzby Jan 31 '20 at 13:42
  • 1
    I looked at it and it didn't seem to quite apply. I don't need to just preserve one variable from a loop. I need to be able to increment two counters, evaluate the string read from the file, evaluate the counters, ECHO the counters and process the current string, all within the FOR loop. All of that needs DelayedExpansion enabled to work properly (at least I don't know any way to it without DE), but DE needs to be off when reading each line from the file. Basically the entire script operates inside the loop, and depends on the variables keeping their values on each iteration. – Bob Smith Feb 01 '20 at 05:50

2 Answers2

0

With Help from dbenham and his answer here, There is a Solution that exists for this Scenario.

The key, as Dave has Shown, is in Setting the variables PRIOR to using SetlocalEnableDelayedExpansion so that ! is preserved.

@echo off
Set "count=0"
    For /F "delims=" %%F in (test.txt) do (
        Call :LineParse "%%~F"
    )

REM The Below Loop demonstrates Preservation of the Values
Setlocal EnableDelayedExpansion
    For /L %%a in (1,1,!count!) DO (
        ECHO(!line[%%a]!
    )
Endlocal

pause
exit

:LineParse
Set /a count+=1
Set "Line[%count%]=%~1"
Setlocal EnableDelayedExpansion
ECHO(!Line[%count%]!
ECHO(Total: !count!
(
ENDLOCAL
)
GOTO :EOF

There are still a few characters that will not be parsed as desired with this Method, noted in test.txt:

test.txt
Safe Characters: ! > * & ` ' . ] [ ~ # @  : , ;  ~ } { ) ( / \ ? > < = - _ + $ |
problem Characters: ^ "" %%

problem examples:
line disappears " from single doublequote
but not "" from escaped doublequote
%% will not display unless escaped. % unescaped Percent Symbols will attempt to expand %
caret doubles ^ ^^ ^^^
T3RR0R
  • 2,747
  • 3
  • 10
  • 25
0

Don't need to complicate...

Just replace:

  • echo/ to set /p

  • setlocal enabledelayedexpansion to cmd /v /c

@echo off 

for /F "delims=" %%F in ('type test.txt')do set /a "Count+=1+0" && (
(echo/ & cmd /v/s/c "set/p "'=!Count! - %%F"<nul")>>".\newfile.txt")
cmd /v /c echo/ Total: !Count! && call set "Count="<nul && goto :EOF
Io-oI
  • 2,514
  • 3
  • 22
  • 29