I am trying to use the index in a for loop and store it in a variable.
I wrote a batch file with this code:
FOR /L %%x IN (1,1,3) DO (
ECHO %%x
SET tmp=prefix_%%x.suffix
ECHO tmp is %tmp%
)
when running it, I get:
1
tmp is prefix_3.suffix
2
tmp is prefix_3.suffix
3
tmp is prefix_3.suffix
i would expect it to be:
1
tmp is prefix_1.suffix
2
tmp is prefix_2.suffix
3
tmp is prefix_3.suffix
what am I doing wrong?!
Setlocal enableextensions enabledelayedexpansion
FOR /L %%x IN (1,1,3) DO (
ECHO %%x
SET tmp=prefix_%%x.suffix
ECHO tmp is !tmp!
)
All the block in the for command is evaluated when it is readed. %%x changes are seen as it is a special variable known to change during loops, but %tmp% is only translated once, at the start and is not reevaluated. Enabling delayed expansion and changing sintax to !tmp! instructs cmd to reevaluate the variable each time it is accessed.
Related
I'm trying to make a batch file I call from another batch file, but the variables don't work, all the results are "a", while the expected result would be option1=a, option2=b, etc.
Here's the code to demonstrate the issue:
call temp.bat a b c d e f g h i j k l m n o p q r s t e u v w x y z
pause
exit
and for temp.bat:
set Number=0
for %%a in (%*) do set /a Number+=1
for /l %%a in (1,1,%Number%) do (
set option%%a=%1
shift
)
exit /b
I've tried !%1! with empty results; %%1% gave "%1" as the result; %1% had the same result as just using %1
You can force another level of indirection by using call. It'll expand %%1 to %1 before evaluating
for /l %%a in (1,1,%Number%) do (
call set option%%a=%%1
shift
)
Batch number variable setter
BAT-file: variable contents as part of another variable
How can I pass a variable name as part of a parameter to a batch file and then use it?
See also an alternative here: Batch-Script - Iterate through arguments
You could do this with one FOR command which would be much more efficient.
Using the CALL Method
#echo off
set Number=0
for %%a in (%*) do (
set /a Number+=1
call set "option%%Number%%=%%a"
)
Using Delayed Expansion
#echo off
setlocal enabledelayedexpansion
set Number=0
for %%a in (%*) do (
set /a Number+=1
set "option!Number!=%%a"
)
Is it possible to square the increment/step variable in a batch for loop.
This is what it looks like right now
FOR /L %%A IN (1024,1000, 1048576) DO (
do stuff
)
however instead of going up by 1000 each time, I want to go up by 2^10, 2^11 .... 2^20 (1048576) is it possible to do that?
No, for /l loops can not handle geometric increments. But you can use batch arithmetics for it
for /l %%a in (10 1 20) do (
set /a "A=1<<%%a"
setlocal enabledelayedexpansion
for %%A in (!A!) do ( endlocal
rem Your code here - do stuff
echo %%A
)
)
Delayed expansion is needed to handle the changing variable inside the block of code. If your inner code has no problems with delayed expansion being active, it can be simplified as
setlocal enabledelayedexpansion
for /l %%a in (10 1 20) do (
set /a "A=1<<%%a"
rem Your code here - do stuff
echo !A!
)
If switching to PowerShell is fine for you, you can use
foreach ($i in 1..3) {
# example output
echo "1000^$i = $([Math]::Pow(1024, $i))"
# start "myprogram.bat --parameter $x
& 'myprogram.bat' #("--parameter", [Math]::Pow(1024, $i))
}
I`m having issues with a batch file I have written to process a large amount of .wav music files with a tool. The encoded format is to have loop start and end points encoded within it.
#echo off
#echo -------CONVERSION---------
for /f "tokens=1-5" %%l in (test.txt) do (
#echo %%n.wavを%%ni.fcoへ変換中です
#echo %%o %%p
set /a endloop1=%%o
set /a endloop2=%%p
set /a endloop=endloop1+endloop2
#echo %endloop1% %endloop2% %endloop%
contool -e -br 144 -loop %endloop1% %endloop% ed%%n.wav ed%%n.fco
And the test.txt file I`m reading values from in its entirety is
bgmtbl BGM_Title 7552 73664 4997136
bgmtbl BGM_GameOver 7534 22464 4014400
bgmtbl BGM_Midtown 7101 773184 3718720
bgmtbl BGM_Cross_1 7102 112838 5827154
Where the fourth and fifth values are the ones I need - the loop start point and loop length
for some reason the endloop values use the numbers from the last line of the text file over and over! e.g
7552.wavを7552i.fcoへ変換中です
73664 4997136
112838 5827154 5939992
your parametter doesn't satisfy under the condition
0<= loopstart(112838) <= loopend(5939992) < Total Sample(5118208) element=0/1
7534.wavを7534i.fcoへ変換中です
22464 4014400
112838 5827154 5939992
your parametter doesn't satisfy under the condition
0<= loopstart(112838) <= loopend(5939992) < Total Sample(4125696) element=0/1
etc
Please help, this is very perplexing!
Another possibility:
#echo off &setlocal
for /f "tokens=1-5" %%l in (test.txt) do (
echo %%n.wavを%%ni.fcoへ変換中です
echo %%o %%p
set /a endloop1=%%o
set /a endloop2=%%p
set /a endloop=%%o+%%p
)
echo %endloop1% %endloop2% %endloop%
Here you do not need delayed expansion. The first access to the %variables% is after the end of the for code block.
#echo off
#echo -------CONVERSION---------
setlocal enableDelayedExpansion
for /f "tokens=1-5" %%l in (test.txt) do (
#echo %%n.wavを%%ni.fcoへ変換中です
#echo %%o %%p
set /a endloop1=%%o
set /a endloop2=%%p
set /a endloop=!endloop1!+!endloop2!
#echo !endloop1! !endloop2! !endloop!
contool -e -br 144 -loop !endloop1! !endloop! ed%%n.wav ed%%n.fco
)
More info : http://www.robvanderwoude.com/variableexpansion.php
I want to read a CSV file line by line and echo something different if the length of the line is 7999.
I manage to do something as below, which reads each line and checks the number of character for each line, but the issue is that I am getting no value in %result% and echo(%result% prints a blank value. Any idea what am I doing wrong here? Thanks
#echo off
setlocal
for /f "tokens=* delims= " %%a in (REPORTS.csv) do (
set "line=%%a"
call :strlen result line
echo(%result%
if %result% EQU 7999 (
echo %%a
echo(short=%result%
) else (
echo %%a
echo(long=%result%
)
pause
)
:strlen <resultVar> <stringVar>
(
setlocal EnableDelayedExpansion
set "s=!%~2!#"
set "len=0"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!s:~%%P,1!" NEQ "" (
set /a "len+=%%P"
set "s=!s:~%%P!"
)
)
)
(
endlocal
set "%~1=%len%"
exit /b
)
Put this section into another subroutine, similar to :strlen
echo(%result%
if %result% EQU 7999 (
echo %%a
echo(short=%result%
) else (
echo %%a
echo(long=%result%
)
Note also that your main routine will continue into your subroutine when finished, so at end-of-file(reports.csv) the batch will execute :strlen one final time and exit through the EXIT
I'd recommend adding a
GOTO :EOF
Immediately before the :strlen label. This is understood by the processor to go to end-of-physiacl-file (the colon is required)
When a compound statement enclosed in parentheses is to be executed,
the statement is first parsed from the open parenthesis all of the
way to the matching close-parenthesis.
At this time, any %var% is replaced by that var's value from the
environment AT THE TIME IT IS PARSED (ie its PARSE-TIME value.)
THEN if the statement seems valid, it is executed.
There are three common ways of accessing the RUN-TIME value of the
variable (as a FOR loop executes, for instance.)
1/ SETLOCAL ENABLEDELAYEDEXPANSION which switches to a mode where
!var! may be used to access the runtime value of var
2/ CALL set var2=%%var%% to set the value of var2 from the
runtime value of var
3/ Executing a subroutine, internal or external within which %var%
will be the runtime value.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%i IN (1 2 3) DO (
ECHO START of run %%i
ECHO using ^!time^! : !time! - PARSE TIME was %time%
CALL ECHO using CALL %%%%TIME%%%% : %%TIME%%
CALL :report
timeout /t 5
ECHO using ^!time^! : !time!
CALL ECHO using CALL %%%%TIME%%%% : %%TIME%%
CALL :report
ECHO END of run %%i
ECHO.
)
GOTO :eof
:report
ECHO :report says TIME is %TIME%
GOTO :eof
A few items to note:
The instruction
IF ERRORLEVEL n echo errorlevel is n OR GREATER
ALWAYS interprets the RUN-TIME value of ERRORLEVEL
IF SET VAR ALWAYS interprets the RUN-TIME value of VAR
The magic variables like ERRORLEVEL and TIME should never
be SET. If you execute
SET ERRORLEVEL=dumb
then ERRORLEVEL will adopt the value dumb because the current
value in the environment takes priority over the system-assigned value.
You should use DelayedExpansion in if and for loops and take care of the brackets:
#echo off
setlocal enabledelayedexpansion
for /f "tokens=* delims= " %%a in (REPORTS.csv) do (
set "line=%%a"
call :strlen result line
echo.!result!
if !result! EQU 7999 (
echo.%%a
echo.short=!result!
) else (
echo.%%a
echo.long=!result!
)
)
pause
goto:eof
:strlen <resultVar> <stringVar>
setlocal EnableDelayedExpansion
set "s=!%~2!#"
set "len=0"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!s:~%%P,1!" NEQ "" (
set /a "len+=%%P"
set "s=!s:~%%P!"
)
)
endlocal &set "%~1=%len%"
exit /b
Your code doesn't ever work in many areas.
I have following code:
#echo off
SET ITER=0
for %%i in (%*) do (
SET ITER+=1
ECHO %ITER%
)
The output is (for three arguments):
0
0
0
Expected output:
1
2
3
Why can't I access the updated variable in the for loop?
Expansion of variables with percents is done before a statement/block is executed.
So in your case the complete block is expanded before the echo %ITER% is executed, to constant echo 0.
The variable ITER itself is updated in the loop properly.
To avoid this, you could use the delayed expansion, this works like percent expansion but just in the moment of execution
#echo off
setlocal EnableDelayedExpansion
SET ITER=0
for %%i in (%*) do (
SET /a ITER+=1
ECHO !ITER!
)