For /L - MORE and @ECHO OFF

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
Liviu
Expert
Posts: 470
Joined: 13 Jan 2012 21:24

Re: For /L - MORE and @ECHO OFF

#16 Post by Liviu » 01 Mar 2014 13:49

Ed Dyreen wrote:Is that not just like a quoting/escaping problem ?
Correct. From Dave's post above http://www.dostips.com/forum/viewtopic.php?p=32776#p32776: "What I can see being difficult to work with is quoting and escape sequences given that there are three levels of implicit CMD /C : 1 level for the outer pipe, 1 level for the FOR /F command IN() clause, and 1 level for the inner pipes within the IN() clause".

Ed Dyreen wrote:The @ is more strange to me, must be some bug :S
Not a bug, it's just that the right-hand side of the pipe - in this case the 'for' loop - runs in a new instance of cmd, which has echo on by default. If you want to turn it off in _that_ instance, then you have to do it explicitly since the 'echo' status is not inherited.

Code: Select all

dir /b /a-d | (echo off & for /F "delims=" %%a in (' findstr "a" ') do echo %%a)

Liviu

einstein1969
Expert
Posts: 976
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: For /L - MORE and @ECHO OFF

#17 Post by einstein1969 » 01 Mar 2014 15:35

Thanks to all!

I now have a little more clearly how things work.

Although I read this, yet I'm not able to understand how things work. :?

Aacini took the goal of the code that I was studying. Exit a For /L loop.

This seem that not close window batch but i have no idea why. And no idea how write on multiline.

Code: Select all

@echo off
setlocal

set /A index=0, sum=0
echo\|cmd /v:on /q /s /c "for /L %%? in (1,1,10) do  (set /a index+=1, sum+=index >nul&echo ^!index^! & if ^!index^! == 5 exit !sum!) "
echo Returned value: %errorlevel%


einstein1969

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: For /L - MORE and @ECHO OFF

#18 Post by Ed Dyreen » 01 Mar 2014 16:17

einstein1969 wrote:Thanks to all!

I now have a little more clearly how things work.

Although I read this, yet I'm not able to understand how things work. :?

Aacini took the goal of the code that I was studying. Exit a For /L loop.

This seem that not close window batch but i have no idea why. And no idea how write on multiline.

Code: Select all

@echo off
setlocal

set /A index=0, sum=0
echo\|cmd /v:on /q /s /c "for /L %%? in (1,1,10) do  (set /a index+=1, sum+=index >nul&echo ^!index^! & if ^!index^! == 5 exit !sum!) "
echo Returned value: %errorlevel%


einstein1969

it is not necessary to escape the exclamation mark, /v:on is executed after the parameters are read

Code: Select all

@echo off &prompt $G &setlocal DisableDelayedExpansion

set $lf=^


::
%=   =%set "$plf=%%$lf%%"

set /A index=0, sum=0
echo\|cmd /v:on /q /s /c ^"for /L %%? in (%$plf%^
%$plf%^
   1,1,10%$plf%^
%$plf%^
) do (%$plf%^
   set /a index+=1, sum+=index ^>nul%$plf%^
   echo !index!%$plf%^
   if !index! == 5 exit !sum!%$plf%^
)"

echo Returned value: %errorlevel%

pause
exit /b

Code: Select all

1
2
3
4
5
Returned value: 15
Druk op een toets om door te gaan. . .
Is this what you mean with; And no idea how write on multiline. ?

Squashman
Expert
Posts: 4488
Joined: 23 Dec 2011 13:59

Re: For /L - MORE and @ECHO OFF

#19 Post by Squashman » 01 Mar 2014 18:41

Discussion from a few years ago about breaking For /L loops.
viewtopic.php?f=3&t=2707&start=0

Aacini
Expert
Posts: 1932
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: For /L - MORE and @ECHO OFF

#20 Post by Aacini » 01 Mar 2014 18:53

I was able to successfully use this idea in order to implement a simpler while loop. You just need to define 4 variables and end each line inside the while body with "%;%".

Code: Select all

@echo off
setlocal DisableDelayedExpansion
set LF=^


rem Previous two empty lines required - do not remove
set ";=%%LF%%^"
set "while=echo/|cmd /V:ON /D /Q /C for /L %%? in () do if"
set "endwhile=) else exit !whileResult!"

set /A index=1, whileResult=0
%while% !index! leq 5 ( %;%
   echo !index! %;%
   set /a whileResult+=index, index+=1 ^>nul %;%
%endwhile%
echo Returned value: %errorlevel%


The only requirement is that Delayed Expansion must be disabled when the %while% be executed.

Antonio

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: For /L - MORE and @ECHO OFF

#21 Post by Ed Dyreen » 01 Mar 2014 20:25

Aacini wrote:The only requirement is that Delayed Expansion must be disabled when the %while% be executed.
It can work regardless delayedState

Code: Select all

@echo off
set LF=^


rem Previous two empty lines required - do not remove
set ";=%%LF%%^"
set "while=echo/|cmd /V:ON /D /Q /C for /L %%? in () do if"
set "endwhile=) else exit ^^^!whileResult^^^!"

setlocal DisableDelayedExpansion
set /A index=1, whileResult=0
%while% ^^^!index^^^! leq 5 ( %;%
   echo ^^^!index^^^! %;%
   set /a whileResult+=index, index+=1 ^>nul %;%
%endwhile%
echo Returned value: %errorlevel%

setlocal enableDelayedExpansion
set /A index=1, whileResult=0
%while% ^^^!index^^^! leq 4 ( %;%
   echo ^^^!index^^^! %;%
   set /a whileResult+=index, index+=1 ^>nul %;%
%endwhile%
echo Returned value: %errorlevel%

pause

Code: Select all

1
2
3
4
5
Returned value: 15
1
2
3
4
Returned value: 10
Druk op een toets om door te gaan. . .
for some reason the first exclamation mark affects the 2nd.

Code: Select all

set "$=cmd /V:ON /C echo.test^^^!&echo.weird^^^!&echo.weird^^^!"
set "$"
%$%
set "$=cmd /V:ON /C echo.weird^^^!&echo.weird^^^!"
set "$"
%$%
pause

Code: Select all

$=cmd /V:ON /C echo.test^^^!&echo.weird^^^!&echo.weird^^^!
test!
weird^!
weird^!
$=cmd /V:ON /C echo.weird^^^!&echo.weird^^^!
weird!
weird^!
Druk op een toets om door te gaan. . .
I don't understand this behavior.

jeb
Expert
Posts: 1063
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: For /L - MORE and @ECHO OFF

#22 Post by jeb » 02 Mar 2014 01:59

Ed Dyreen wrote:for some reason the first exclamation mark affects the 2nd.

No, but the "&" doesn't concat the echo's inside the CMD /C, instead it splits the line into

Code: Select all

cmd /V:ON /C echo.test^^^!
echo.weird^^^!^
echo.weird^^^!"


Escaping the ampersands works

Code: Select all

set "$=cmd /V:ON /C echo.test^^^!^&echo.weird^^^!^&echo.weird^^^!"
%$%

jeb

einstein1969
Expert
Posts: 976
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: For /L - MORE and @ECHO OFF

#23 Post by einstein1969 » 02 Mar 2014 07:06

@Ed: Yes Is what i want to do. In single line i have leave the escape for work regardless delayedState. I like your multiline code that execute regardless delayedState. It is finished?

@Aacini: The while loop is very, very nice!!!!!! I like that syntax (ie %;%). Is like pascal , jscript , c ....

@jeb: Thank God you're there! :D

einstein1969

einstein1969
Expert
Posts: 976
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: For /L - MORE and @ECHO OFF

#24 Post by einstein1969 » 02 Mar 2014 08:09

Hi, I worked with version with disabled delayed expansion because the syntax is more readable and I STILL do not see the need of enable delayed expansion.

my generic code:

Code: Select all

@echo off &setlocal DisableDelayedExpansion

set lf=^


::
set ";=%%lf%%^"
rem set _FOR_L_BREAK_PIPED_=echo/^>nul^|cmd /v:on /D /Q /C for /L
set _FOR_L_BREAK_PIPED_=break^|cmd /V:ON /D /Q /C for /L

set t0=%time%

set /A index=1, sum=0, last=25000

%_FOR_L_BREAK_PIPED_% %%? in (1,1,100000) do (  %;%
   set /a index+=1, sum+=index ^>nul            %;%
   echo !index! - %%? - !sum!                   %;%
   if !index! == !last! exit !sum!              %;%
) ^>nul %_END_FOR_L_BREAK_PIPED_% 

echo Returned value: %errorlevel%

for /F "tokens=1-8 delims=:.," %%a in ("%t0: =0%:%time: =0%") do set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000"
echo Elapsed: %a%cs

pause
exit /b


It is possible change state of delayed expansion programmatically?

Ie. If enabled than disable else nothing.

And restore the status at the end of FOR?

It is possible include in variables %*FOR_L_BREAK_PIPED_% the code?

thanks.

@Aacini: why use echo/? And not echo(?

Einstein1969

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: For /L - MORE and @ECHO OFF

#25 Post by Ed Dyreen » 02 Mar 2014 08:24

einstein1969 wrote:It is possible change state of delayed expansion programmatically?

Ie. If enabled than disable else nothing.

And restore the status at the end of FOR?
You are already local inside your while loop ( cmd /v:on ), the status is already restored automatically.
To be precise; There is nothing to restore to, you were running an isolated child instance of cmd.
Therefor you can only communicate back to the caller directly by setting exitCode.
Indirectly you can for example process the visual feedback returned by your child cmd instance.

Aacini
Expert
Posts: 1932
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: For /L - MORE and @ECHO OFF

#26 Post by Aacini » 02 Mar 2014 08:46

einstein1969 wrote:Hi, I worked with version with disabled delayed expansion because the syntax is more readable and I STILL do not see the need of enable delayed expansion.

As a matter of fact, you will never need it! Commands inside the while body are executed in a separate cmd.exe context and the delayedState is Enabled upon entering the while, so there is no reason to Enable Delayed Expansion before the %while%.
einstein1969 wrote:It is possible change state of delayed expansion programmatically?

Ie. If enabled than disable else nothing.

And restore the status at the end of FOR?

Yes. Just execute "setlocal DisableDelayedExpansion" inside the while body. Previous delayedState will be automatically reset when the while ends, because it is executed in a separate cmd.exe context.
einstein1969 wrote:@Aacini: why use echo/? And not echo(?

I don't like "echo(" syntax because it is confusing. When I review a program, the "(" always catch my attention and I have to spent additional time to check that it is correct. This syntax is needed if and only if a variable follows and this variable may contain certain special characters, like "/?". In any other case, I use "echo/" syntax that is much more readable, because "/" character is commonly used in all commands.

Question: Why you don't use the %while% loop as I wrote it?

Antonio

Squashman
Expert
Posts: 4488
Joined: 23 Dec 2011 13:59

Re: For /L - MORE and @ECHO OFF

#27 Post by Squashman » 02 Mar 2014 09:13

Einstein read the help for cmd.exe. You will see that the code is turning on delayed expansion.
http://ss64.com/nt/cmd.html

einstein1969
Expert
Posts: 976
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: For /L - MORE and @ECHO OFF

#28 Post by einstein1969 » 02 Mar 2014 09:26

Sorry I have explained myself badly. I was referring to the following case in which for some reason was enabled delayed expansion.

Code: Select all

@echo off&goto :Init_system

   Comments Comments Comments Comments
   Comments Comments

:Main

set t0=%time%

set /A index=1, sum=0, last=5000

setlocal DisableDelayedExpansion

%_FOR_L_BREAK_PIPED_% %%? in (1,1,100000) do (  %;%
   set /a index+=1, sum+=index ^>nul            %;%
   echo !index! - %%? - !sum!                   %;%
   if !index! == !last! exit !sum!              %;%
) ^>nul %_END_FOR_L_BREAK_PIPED_% 

endlocal

echo Returned value: %errorlevel%

for /F "tokens=1-8 delims=:.," %%a in ("%t0: =0%:%time: =0%") do set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000"
echo Elapsed: %a%cs

pause
exit /b


:Init_system

setlocal DisableDelayedExpansion

set lf=^


::
set ";=%%lf%%^"
rem set _FOR_L_BREAK_PIPED_=echo/^>nul^|cmd /v:on /D /Q /C for /L
set _FOR_L_BREAK_PIPED_=break^|cmd /V:ON /D /Q /C for /L

setlocal EnableDelayedExpansion

goto :Main


thanks

@Aacini: Thanks for explain use of echo(. I use this version of FOR because i want use the variable %%? of the cicle. For performace reason mainly.

EDIT:There was an error on code. I have correct.

einstein1969

einstein1969
Expert
Posts: 976
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: For /L - MORE and @ECHO OFF

#29 Post by einstein1969 » 02 Mar 2014 16:35

I have modified a little the Aacini's WHILE LOOP for export the variable WhileResult to external context

It's safe?

Code: Select all

@echo off
setlocal DisableDelayedExpansion
set LF=^


rem Previous two empty lines required - do not remove
set ";=%%LF%%^"
set "while=(break|cmd /V:ON /D /Q /C for /L %%? in (^) do if"
set "endwhile=) else exit !whileResult!) & (call set whileResult=%%errorlevel%% & cmd /V:ON /C exit /b !whileResult!)"
set "do=(%;%"

set /A index=1, whileResult=0
%while% !index! leq 5 %do%
   echo !index!                                 %;%%_WHILE_BODY_do_not_put_space_after_this%
   set /a whileResult+=index, index+=1 ^>nul    %;%
%endwhile%
echo Returned value: %errorlevel% %whileResult%


result:

Code: Select all

1
2
3
4
5
Returned value: 15 15


EDIT: seems work without pipe too: Why? :?

Code: Select all

set "while=(cmd /V:ON /D /Q /C for /L %%? in (^) do if"


EDIT2: Correct a BUG. Modified || with &


einstein1969

Post Reply