variable is not assigned in for loop despite EnableDelayedExpansion - batch-file

I have the following batch script that is supposed to generate filenames on the fly. Unfortunately I can't get the function to assign a return value to filename. Each echo returns an empty line.
#echo off
setlocal EnableDelayedExpansion
for /l %%i in (0,1,1) do (
call :create_filename %%i filename
echo(!%filename%!
)
pause
:create_filename
set "base=My test file"
if %1 GTR 0 set "base=%base% (%1)"
set "%~2=%base%.txt"
GOTO :eof

Using delayed variables require you to refer to them with !Var! syntax rather than %Var% syntax. %Var% remains expanded at readtime. !Var! are expanded at execution time. Set DelayedExpansion just turns on support for!Var!.

Related

using incremented variable in echo statement batch file without modifying it again and again

I am using command prompt in windows 7 but my question should apply for any windows version xp and above.
I am using a variable but want to echo incremented value in an echo statement .
Currently , I increment then echo then decrement variable as shown below
set /a count=<some value>
set /a count+=1
echo %count%
set /a count-=1
Process count having <same value>
I hope there is a better way to increment the value of the variable by just using echo.
Thanks.
You want something effectively like echo %count%+1? No, this won't work. The only way to do math in cmd is the set /a command.
I personally won't touch my original variable but use a dummy var;
set /a xcount=count+1
echo %xcount%
(just a thing of personal preference).
What actually would work:
set /a count=5
cmd /c set /a x=count+1
cmd /c set /a x=count+1 & echo/ this is plus one
cmd /c "<nul set /p "x=%Count% plus one is " & set /a x=count+1 &echo/. Ready."
echo %count% is still 5
because the set command is then done (in a new process) directly "on the command line" and set /a shows the result when done on the command line (but doesn't show the result in a batch file).
Contra: It's quite easy to show just the number (first cmd... line), but if you want to put some text "around", it quickly gets ugly (second line to append text, third line to put text around the number). And you open a new process. If you do it in a loop (as the variable name count suggests), it may slow down your script considerably.
You could use delayed expansion, via SETLOCAL and ENDLOCAL, without creating an intermediate variable or running another instance of cmd.exe.
Rem Ensure extensions are enabled for SET /A functionality
Rem and disable delayed expansion.
SetLocal EnableExtensions DisableDelayedExpansion
Rem Define variable named count with the string value of an integer
Set "count=5"
Rem Print the value
Echo %count%
Rem Enable delayed expansion
SetLocal EnableDelayedExpansion
Rem increment the variable value
Set /A count += 1
Rem Print the new value
Echo !count!
Rem Discard variables defined or modified during previous SETLOCAL
EndLocal
Rem Print the value
Echo %count%
#Rem Optional PAUSE for GUI invoked script
#Pause
A for /f loop is another means that avoids delayed expansion or setlocal / endlocal which can be used to get offset values without modifying the original count:
#Echo off
For %%O in (+ -)Do for /f "Delims=" %%G in ('Set /A "count%%O=1"')Do Echo(%Count% %%O 1 = %%G

Batch: How to replace % sign within a variable?

I'm trying to rename my files to remove any characters that cause problems in scripts. This works well for ampersand and exclamation point but when the file has the percent sign it doesn't show up in the variable to begin with. How do I pass files with special characters via for loop?
for %%v in (*) do call :validate "%%v"
exit /b
:validate
set "original=%~nx1"
set "newtitle=%original:!=%"
set "newtitle=%newtitle:&=and%"
setlocal enabledelayedexpansion
set "newtitle=!newtitle:%%= percent!"
if not "%newtitle%"=="%original%" ren %1 "%newtitle%"
Your problem is the line for %%v in (*) do call :validate "%%v", because thecall` starts the parser a second time and there all percents are evaluated a second time.
You should save the value into a variable and access these variable in your function instead.
setlocal DisableDelayedExpansion
for %%v in (*) do (
set "filename=%%~v"
call :validate
)
exit /b
:validate
setlocal EnableDelayedExpansion
set "original=!filename!"
set "newtitle=%original:!=exclam%"
set "newtitle=!newtitle:&=and!"
set "newtitle=!newtitle:%=percent!"
A possible way is to use delayed expansion:
set "newfilename=%filename:&=and%"
setlocal EnableDelayedExpansion
set "newfilename=!newfilename:%%= percent!"
endlocal
The %-sign must be escaped by doubling it in a batch file.
Note that the variable is no longer available beyond the endlocal command.
I used the quoted syntax, which is the safest way to define variables, even with white-spaces and special characters.

BATCH, summarize variables inside FOR loop

I have a batch file with a FOR loop inside like this:
set /a target=5
FOR /L %%G IN (1,1,%target%) DO (
echo %%G)
It works like a charm %%G will 1,2,3,4,5.
Now I want a new wariable like test=%%G+1 and it will be: 2,3,4,5,6
But with this code it didn't works.
set /a target=5
FOR /L %%G IN (1,1,%target%) DO (
echo %%G
set /a test=%%G+1
echo %test%
)
test variable will be every time: 6
What should I do?
Thanks
Roberto
You need to use EnabledDelayedExpansion when evaluating variables which are set inside a FOR loop:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
set /a target=5
FOR /L %%G IN (1,1,%target%) DO (
echo %%G
set /a test=%%G+1
REM Note the exclamation marks.
REM This is delayed expansion notation.
echo !test!
)
ENDLOCAL
If you do not use delayed expansion, then all variables are evaluated on the first pass of the FOR loop, so %test% will not actually have a value at this time.
By turning on delayed expansion (and using the !test! notation), the script will evaluate the value of !test! on each pass.

Windows Batch file processing - Loops

Am very new to batch scritping. I just tried to execute the below code for which am totally confused.
#echo off
set m=100
set i=0
FOR /L %%N IN (0,1,%m%)do (
set /a i=1+%i%
)
echo %i%
pause
Here, am incrementing i value until N reaches 100. So, am expecting the value of i at the end of loop to be 101 but it shows 1. Can anyone explain what's the reason behind this.
thanks
You need delayed expansion : http://www.robvanderwoude.com/variableexpansion.php
#echo off
setlocal enableDelayedExpansion
set m=100
set i=0
FOR /L %%N IN (;;0,1,%m%;;) do (
set /a i=1+!i!
)
endlocal & set /a i=%i%
echo %i%
In batch files, variable reads are replaced with their values at parse time, before executing the line or the block (code enclosed in parenthesis).
So, the %i% reference inside the for loop is replaced with the value of the variable before the for loop, that is, 0 , and %m% is replaced with 100, and what gets executed is
for /l %%n in (0 1 100) do ( set /a i=1+0 )
You can enable delayed expansion (setlocal enabledelayedexpansion command) and change the sintax from %i% to !i! to indicate the parser that reads to the variable should be delayed until the moment of executing the line. The code should be
#echo off
setlocal enabledelayedexpansion
set m=100
set i=0
FOR /L %%N IN (0,1,%m%)do (
set /a i=1+!i!
)
echo %i%
endlocal
The read of the value of i inside the for loop is delayed. This way, the real value is readed just before each execution of the line. Reference to i out of the loop does not need it. When the line is reached and parsed, the correct value is retrieved and echoed.
Anyway, while this is the general rule, set /a has a different behaviour. If you change your code to
set /a i+=1
or
set /a i=i+1
the parser will correctly identify the operation and execute the expected code with or without delayed expansion enabled.

Temporarily interrupt SETLOCAL

I have a script that has a lot of use of the SETLOCAL ENABLEDELAYEDEXPANSION command, so I start the script off that way (less headaches). However, it does not allow you to use the ! character without escaping each instance of it (and I want to create a long line of !s for an error logging section =D ) and I don't want to escape every one of them.
Is there a way to temporarily break out of SETLOCAL, then reenter it keeping all previously created variables within the original SETLOCAL?
For example:
SETLOCAL ENABLEDELAYEDEXPANSION
set var=HELLO
ECHO %var%
ENDLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO %var%
The 2nd ECHO will not give you the previous value of var
EDIT: ^ will not allow you to escape the ! inside SETLOCAL ENABLEDELAYEDEXPANSION
setlocal DisableDelayedExpansion
set var=Value! with! many! Bangs!
setlocal EnableDelayedExpansion
echo !var!
You can nest it like Aacini shows it.
Or you can use the return technic or escape ! inside a EnableDelayed block with ^^!
Setlocal EnableDelayedExpansion
echo 1^^!^^!^^!^^!^^!^^!^^!
REM *** Or use a self removing quote
echo !="! 2^!^!^!^!^!^!
Setlocal DisableDelayedExpansion
echo 3 !!!!!!!!
set var=Hello
(
endlocal
rem Bring the value behind the endlocal barrier
set var=%var%
)
echo var is still there, %var%
The return technic can also be used for exclamation marks, but then it is a bit more complex.
It can be found at Make an environment variable survive ENDLOCAL

Resources