1

I'm trying to create a program where I go through files (in a folder and all its sub folders) and dynamically replace parts of a line with other parts. To do this I made a program but found out that it behaved unexpectedly.

Instead of just the string being replaced the WHOLE line got replaced. Then I did some experiments and saw that outside of the loops the string replacement behaved as expected but inside.......strangeness began.

Below is a pretty basic example with a normal string replacement inside a loop.

@echo off   
call :Rekursiv
goto :eof

:Rekursiv
    set str=teh cat in teh hat
    echo "Outside"
    echo %str%
    set str=%str:teh=the%
    echo %str%  
    echo "Outside end"

    for /D %%d in (*) do (
            cd %%~fd

            set str=teh cat in teh hat
            echo %str%
            set str=%str:teh=the%
            echo %str%      

            call :Rekursiv      

            cd..
    )

    exit /b     

Now normally I would expect:

teh cat in teh hat
the cat in the hat

and a few outside and outside end strewn in between, but what I get is:

"Outside"
teh cat in teh hat        <--- as expected
the cat in the hat        <--- as expected
"Outside end"
the cat in the hat        <--- Completely unexpected as its the replaced string already!
the cat in the hat
"Outside"
teh cat in teh hat
the cat in the hat
"Outside end"
the cat in the hat
the cat in the hat
"Outside"
teh cat in teh hat
the cat in the hat
"Outside end"
the cat in the hat
the cat in the hat
"Outside"
teh cat in teh hat
the cat in the hat
"Outside end"

All replacements outside the loops work as I thought they should. But inside the loop it looks like the sets are all done BEFORE the echoes are done. As I think this and my line replacement problem have the same source/cause my question is here: WHY does the program produce this unexpected output? And what can I do to get the expected output?

EDIT: After MCDNs comment I tried things out:

@echo off   
call :Rekursiv
goto :eof

:Rekursiv
    set str=teh cat in teh hat
    echo "Outside"
    echo %str%
    set str=%str:teh=the%
    echo %str%  
    echo "Outside end"


set "test=before"
if defined test (
    set "test=after"
    echo %test%
)   

    for /D %%d in (*) do (
            cd %%~fd

            set str=teh cat in teh hat
            echo %str%
            set str=%str:teh=the%
            echo %str%      

set "test=before"
if defined test (
    set "test=after"
    echo %test%
)

            call :Rekursiv      

            cd..
    )

The first occurance of "echo %test%" is "before" the second is "after"

Thomas
  • 2,886
  • 3
  • 34
  • 78
  • Maybe [this](http://stackoverflow.com/a/30177832/2861476) could help – MC ND Oct 07 '15 at 06:47
  • @MCND Hmmmm interesting point. Outside of a loop I get it. But inside the loop it is "after" do you know why there? ("before" I would expect as it is the same outside the loop but I get after inside the loop). moment will update the solution there. – Thomas Oct 07 '15 at 06:55
  • Ah maybe I understand it. Can it be so that: 1st occurance is before then thogh the if set comes into effect thus the 2nd echo is set to after because of this? (as it parses the second %test% before looking at the "test=before" before that?) – Thomas Oct 07 '15 at 06:58

1 Answers1

0

Short: Percent expansion is done BEFORE a block will be executed, while parsing.

You can see the block with fixed strings before anything is executed inside.

Therefore the delayed expansion exists, this is evaluated when a single command is executed.
The syntax is nearly the same, but instead of percent signs exclamation marks are used.
But before you can use delayed expansion it must be enabled with

setlocal EnableDelayedExpansion

So your code would look like

@echo off   
setlocal EnableDelayedExpansion
call :Rekursiv
goto :eof

:Rekursiv
    set str=teh cat in teh hat
    echo "Outside"
    echo %str%
    set str=%str:teh=the%
    echo %str%  
    echo "Outside end"

    for /D %%d in (*) do (
            cd %%~fd

            set "str=teh cat in teh hat"
            echo !str!
            set str=!str:teh=the!
            echo !str!
    )
jeb
  • 78,592
  • 17
  • 171
  • 225