How show environment var !content! (delayed expansion) inside a FOR loop?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
MicrosoftIsKillingMe
Posts: 55
Joined: 11 Dec 2017 09:08

How show environment var !content! (delayed expansion) inside a FOR loop?

#1 Post by MicrosoftIsKillingMe » 22 Dec 2017 23:25

For the code shown below I want to normally have echo off, but turn echo on to test and debug, and not have to modify individual lines for that - just make that one change to ECHO, and run. In particular I want to see the current (delayed expansion) value of !state! when echo is on, else display nothing.

echo !state! displays something when echo is off so no good.
rem !state! just shows the 7 letter string !state! so no good. Too bad; this would have been perfect.
set state=!state! surprises me that it also doesn't show the expansion.

Apparently, what is displayed when you run a FOR loop with echo on, is first an echo of the FOR and its DO block, and then more echos of lines, this time showing each line in the block that is to be run (even though they look almost identical to the first lines displayed); but there's only the FOR loop variable expansion at that time, not environment variables. Running the code below, the LOOP variable %i performs perfectly (shows its expanded value even in a REM). But !state! content is hard to display.

BTW I know that I could use IF or GOTO logic to conditionally ECHO !state! using a boolean, but would prefer not to add the "noise".

Experience tells me that someone will say that I can already see !state! when I set it to begin with below, but that's just an artificiality of the silly example I built to help you see what I'm shooting for - which is how to see !somevar! in a FOR loop, while ECHO is on, without using ECHO !somevar!.

Code: Select all

rem echo off
set state=NO
setlocal enabledelayedexpansion
for /F %%i in ('dir^| findstr /C:"Directory"') do (
  rem i is %%i
  set state=yes
  echo state is !state! & rem eventually expands but shows during echo off
  set state=!state!     & rem doesn't visibly expand
  rem state is !state!  & rem doesn't visibly expand
  rem state is %state%  & rem expands the "wrong" thing, undelayed
)
rem The following SET lines are to be removed; are just FYI for this post
set state
endlocal
set state
OUTPUT:

Code: Select all

C:\>rem echo off

C:\>set state=NO

C:\>setlocal enabledelayedexpansion
C:\>for /F %i in ('dir| findstr /C:"Directory"') do (
rem i is %i
 set state=yes
 echo state is !state!   & rem eventually expands but shows when echo off
 set state=!state!       & rem doesn't expand
 rem state is NO  & rem expands the wrong thing
 rem state is !state!  & rem doesn't expand
)

C:\>(
rem i is Directory
 set state=yes
 echo state is !state!   & rem eventually expands but shows when echo off
 set state=!state!       & rem doesn't expand
 rem state is NO  & rem expands the wrong thing
 rem state is !state!  & rem doesn't expand
)
state is yes

C:\>set state
state=yes

C:\>endlocal

C:\>set state
state=NO

MicrosoftIsKillingMe
Posts: 55
Joined: 11 Dec 2017 09:08

Re: How show environment var !content! (delayed expansion) inside a FOR loop?

#2 Post by MicrosoftIsKillingMe » 23 Dec 2017 00:15

My interpretation here is that the second "group" display (of the 6 lines in a parenthetical block) in the output, is that they are echoing what is "about do be" done "as a group" rather than echoing what actually happening post-expansion. That is, that the assignment and expansion of environment variables really hasn't been done yet; thus there's no way that I will be able to see !state! as "YES" because the loop hasn't actually run yet; only the LOOP variable expansion has been done when those commands appear for the second time on the screen. Is that correct?

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: How show environment var !content! (delayed expansion) inside a FOR loop?

#3 Post by aGerman » 23 Dec 2017 06:26

What you observe is what makes debugging of FOR loops complicated.
The first groop shows the whole loop because the interpreter takes it as one command.
The second groop shows the parenthesized body of the loop. Again the interpreter takes it as one command and it shows up for every iteration of the loop. At that point the early expansion of variables surrounded with percent signs is still in place.
Only if the lines are executed the variables surrounded in exclamation marks are expanded.
See https://stackoverflow.com/questions/409 ... e-scripts/

ENDLOCAL ends the subenvironment created by SETLOCAL. Variables set or changed in this subenvironment are not valid anymore. Use

Code: Select all

endlocal &set "state=%state%"
or

Code: Select all

(
  endlocal
  set "state=%state%"
)
to get the values to the parent environment.

Steffen

pieh-ejdsch
Posts: 240
Joined: 04 Mar 2014 11:14
Location: germany

Re: How show environment var !content! (delayed expansion) inside a FOR loop?

#4 Post by pieh-ejdsch » 23 Dec 2017 09:54

Hello,
The real problem is that the variable to be displayed has to be put in an exclamation mark in another loop in order to resolve it, at least with rem.
the second loop is then displayed again and confuses a bit more. There are also a few new brackets with, which are again shown separately.
Now you have to weigh between writing a lot and debugging a lot.

Code: Select all

echo on
setlocal
set in=empty
for %%i in (1) do (
  setlocal enabledelayedexpansion
  set in=full
  rem i = %%i
  rem in = !in!
  echo rem in = !in!
  endlocal
  set in=full
)
set in

rem 2
set in=empty
for %%i in (1) do (
  set in=full
  rem i = %%i
  setlocal enabledelayedexpansion
  @for /f delims^=^ eol^= %%. in ("!in!") do (
    rem setlocal enabledelayedexpansion
    if :!! == : endlocal
    rem in = %%.
    rem endlocal
  )
)
set in

rem 3
set in=empty
for %%i in (1) do (
  rem see debug in next parentheses
  @(
    set in=full
    rem delayedexpansion must enabled befor For loop
    if NOT :!! == : setlocal enabledelayedexpansion
    for /f delims^=^ eol^= %%. in ("!in!") do (
      if :==. set in=full
      if :==. setlocal enabledelayedexpansion
      rem i = %%i
      rem in = %%.
      if :!! == : endlocal
    )
  )
)

set in

pause
Phil

MicrosoftIsKillingMe
Posts: 55
Joined: 11 Dec 2017 09:08

Re: How show environment var !content! (delayed expansion) inside a FOR loop?

#5 Post by MicrosoftIsKillingMe » 23 Dec 2017 11:39

Okay, and thank you for confirming that I wasn't just badly misunderstanding the sequence or missing something painfully obvious. Although I've only begun using delayed expansion for a couple of days I've spent something like 8 hours intensely googling and tearing into experiments with it - but it seems like half of that was in trying to debug FOR loops. (BTW what I posted is a tremendous simplification of my "mad scientific experiments") Indeed expansions in FOR loops are tough for me to debug so it was kind of you to verify that it wasn't "just me."

That link you supplied (https://stackoverflow.com/questions/409 ... e-scripts/) has some tremendously RICH detail on parsing and sequence. That alone is the most valuable part of any answer I've gotten here! People like you and squashman and dbenham and jfl seem to just effortlessly fly through explanations of complex parsing substitutions on some posts - I've studied dozens of them in awe - and often my head spins trying to keep up (leading me to yet more hours of trial and testing) -- but that link looks really, really helpful in mastering the fine points of the batch processing mechanics.

It's really cool when it makes more sense - like the swap (Set "var1=%var2%" & set "var2=%var1%") mentioned on the ss64 delayed expansion page, and the endlocal trick. Much of this vividly reminds me of gnarly experiences with "side effects" which some of you (the mere mortals, anyway :) ) may have been rudely bitten by when first using a new source language and its assignment statements. And of foo(++i), foo(i++).

Thanks again for your time and the detailed and informative answer.

Post Reply