There are 3 files in 'D:\log' folder, which names are 'log1.txt log2.txt log3.txt' respectively. I want to show some infomations by using 'FOR' MS-DOS command.
set /a C=0
for %%I in (log*.txt) do (
echo "%C%--%%I"
set /a C+=1
)
Output strings were like this
0--log101105.txt
0--log101116.txt
0--log101117.txt
But, Expected outputs are like belows not aboves
0--log101105.txt
1--log101116.txt
2--log101117.txt
How to increase value of parameter 'C' while FOR loop?
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set /a c=0
for %%I in (log*.txt) do (
echo "!C!--%%I"
set /a c=!c!+1
)
vYou need to enable "delayed variable expansion" for this.
Check out the help for the SET statemen (SET /?).
It explains exactly your problem
Related
I am still struggling to properly understand the behaviour of Disable/EnableDelayedExpansion...
I want to parse input arguments when calling something like command -a -b -c file such to finally have options=-a -b -c and filename=file.
To do so I use the FOR /f loop:
set "count=0"
set "opts="
set "fl="
set tmpv=
:argloop
for /f tokens^=1^,^*^ delims^= %%a in ("%1") do (
echo.
echo Chosen option is %1
set /a count+=1
echo.
echo Reading %count% is %%a..
set "tmpv=%%a"
rem setlocal enabledelayedexpansion
echo Tmp is %tmpv% after set equal %%variable.
rem endlocal
rem setlocal disabledelayedexpansion
set "tmpv=%tmpv:-=%"
rem setlocal enabledelayedexpansion
echo After removing it writes !tmpv!
rem endlocal
rem setlocal disabledelayedexpansion
if "%tmpv%"=="%%a" (
echo Input does not contain "-"
set "fl=%tmpv%"
echo %fl%
) else (
echo/Options before are %opts%
echo.
if "%opts%"=="" (
echo Options are empty.
set opts=%%a
) else (
set "opts=%opts% %%a"
)
)
if not "%2"=="" (shift & goto:argloop)
)
echo.
echo Finally options are %opts%
set opts=%opts:-=/%
echo Finally options are %opts%
echo File name %fl%
set tmpv=
set count=
goto:end
Output writes:
Chosen option is -a
Reading 1 is -a..
Tmp is after set equal %variable.
After removing it writes
Options before are
Options are empty.
Chosen option is -b
Reading 2 is -b..
Tmp is -= after set equal %variable.
After removing it writes -=
Options before are -a
Chosen option is -c
Reading 3 is -c..
Tmp is = after set equal %variable.
After removing it writes =
Options before are -a -b
Chosen option is flfl
Reading 4 is flfl..
Tmp is = after set equal %variable.
After removing it writes =
Options before are -a -b -c
Finally options are -a -b -c flfl
Finally options are /a /b /c flfl
File name
I had made it working with EnableDelayedExpansion, but not capable of storing final %fl% variable.
But why does it not work this way (without using delayed expansions)??
I will sincerely appreciate whom will try to clarify it in all extents.
The rules really aren't too hard.
You are aware that %var% is resolved to the value of var.
When a loop is parsed, every %var% within that loop is replaced by the THEN-current value of var. This includes pseudovariables like %cd%, %errorlevel% and %random%.
If delayedexpansion is in effect (and it is "in effect" from the setlocal enabledelayedexpansion instruction [start-of-setlocal-bracket] until an endlocal or end-of-file [end-of-setlocal-bracket] is reached) then !var! is resolved to the contents of var at the time that particular instruction (set, echo, etc) is executed.
If delayedexpansion is NOT in effect then !var! is simply that - the literal string !var!.
And one small kink. Any change made to the environment (addition, deletion or variation of variable values) is discarded when a setlocal bracket ends.
So, in all probability, you could display the difference by echoing %var% alongside !var!
and %%x (a metavariable) is always resolved to its current value, regardless of setlocal status.
[After responses]
Since all setlocal enabledelayedexpansion/endlocal brackets are remmed-out in the published code, I'm not surprised at the results.
However, running the published code does not yield the published results - for me, the response was "Reading 0"..."Reading 3".
So, looking at the for loop, I believe it's equivalent to
for /f "tokens=1,* delims=" %%a in ("%1") do (
which in turn is the same as
for /f "delims=" %%a in ("%1") do (
since there are no delimiters, an this is effectively the same as
for %%a in (%1) do (
which does nothing beyond assigning %1 to %%a and making the entire loop one block statement.
So therefore, this code should do the same job - without the kinkiness afforded by setlocal...
#ECHO OFF
SETLOCAL
set "count=0"
set "opts="
set "fl="
set "tmpv="
:argloopn
SET "arg=%1"
IF NOT DEFINED arg GOTO report
SET /a count+=1
ECHO arg %count% is %1 IN variable ARG = "%arg%"
SET "tmpv=%arg%"
rem remove "-"
set "tmpv=%tmpv:-=%"
IF "%tmpv%"=="%arg%" (
echo Input does not contain "-"
set "fl=%tmpv%"
) ELSE (
ECHO Input contains "-" so is option
SET "opts=%opts% %arg%"
)
SHIFT
GOTO argloopn
:report
rem fix-up options since 1st char, if it exists must be a space as [space]newoption is added each time
IF DEFINED options SET "options=%options:~1%"
echo Finally options are %opts%
set opts=%opts:-=/%
echo Finally options are %opts%
echo File name %fl%
echo.
GOTO :EOF
I've assumed that a proper batch-debug environment has been established; hence goto :eof to terminate the batch and an inintial setlocal to preserve the original environment.
When you use the point-click-and-giggle method of executing a batch, the batch window will often close if a syntax-error is found. You should instead open a 'command prompt' and run your batch from there so that the window remains open and any error message will be displayed.
--- BUT ---
In testing, I tried this:
#ECHO OFF
:parasite
setlocal
set "opts="
:loopp
FOR /f "delims=" %%a IN ("%1") DO (
SET "opts=%opts% %%a"
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO OPTS was "%opts%" is now "!opts!"
ENDLOCAL
ECHO %%opts%% is "%opts%" and !opts! is "!opts!"
)
SHIFT
IF "%1"=="" GOTO :EOF
GOTO loopp
Which didn't do what I expected it to do - that is, report
%opts% is " -a -b -c file" and !opts! is "!opts!"
Instead, it reported
%opts% is " -a -b -c file" and -a -b -c file is " -a -b -c file"
Which I find puzzling as the !var! is outside the setlocal enabledelayedexpansion/endlocal command-bracket and hence should not have been replaced, in my view.
Seems like an #jeb problem to me... so I'll see whether he's got an explanation...
I am working on a script which iterates over every file in a specific folder and reads some information from, and numbers each.
So I am running over the files with a for-loop and that is working correctly. Now I added a variable i which should increment on each iteration of the loop.
I used set /a i=0 and inside the for-loop set /a i+=1 and this Set command does print the number to console. My problem now is that the set command prints the number, but when I echo the number with echo %i% it will always print 0 and not the increasing value. I also tried echo !i! but that does not work at all. It just prints !i! in the console.
I also added a pause command to the end of the script, but that gets ignored entirely.
This is my batch script:
#echo off
setlocal EnableDelayedExpansion
set /a i=0
for /r %%n in (Links\*.lnk) do (
set /a i+=1
echo.
echo [Button!i!Back]
get.bat "%%n"
)
pause
This is an example of the output:
45
[Button!i!Back]
###HudIcons\VLC media player.ico
D:\Programme\VideoLAN\VLC\vlc.exe
I also just realized, that for the first time the loop runs, the !i! does work correctly and prints the number, but not afterwards.
I know that I should probably not be calling the other batch file like this, but that is temporary.
Any ideas why this is behaving so weird?
Perhaps it would be easier for you without the Set /A incrementing method, and therefore no need for delayed expansion. The alternative methodology could involve using findstr.exe to provide the counting:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Tokens=1,* Delims=:" %%G In ('Dir /B /S /A:-D "Links\*.lnk" ^
2^> NUL ^| %SystemRoot%\System32\findstr.exe /EILN ".lnk"') Do (Echo=
Echo [Button%%GBack]
Call "get.bat" "%%H")
Pause
You use percentages symbol to call a variable %Variable%
and to echo it echo %variable%
to set one set variable=value Hope this helps you.
Apologies if duplicate, but no other answers so far have helped.
All I'm trying to do is loop through the files in a folder, and rename the last part of the file/extension.
Simply put - there could be 1-90 files, [filename]_01 - [filename]_90, and each day (via windows event scheduler) the number has to increment by one.
Nothing I do seems to achieve this.
The files are also meant to behave slightly differently when they hit certain milestones (30-60-90) but this I believe should already work if the variables update properly.
I have tried so many possible combinations of variable addressing (!variable!/%variable%/etc.) and while I can enter the loop, it does not repeat, nor update the variable number for the end of the files.
SetLocal EnableDelayedExpansion
set cnt=0
for %%A in (*) do set /a cnt+=1
set /A fileNumber = %cnt%-1
set /A newFileNumber = %cnt%
echo %fileNumber%
echo %newFileNumber%
for /l %%F in (%fileNumber%,1,1) do (
if %newFileNumber%==90 (
ren "*_%fileNumber%.don" "*_%newFileNumber%.csv"
)
if %newFileNumber%==60 (
ren "*_%fileNumber%.don" "*_%newFileNumber%.csv"
)
if %newFileNumber%==60 (
"ren *_%fileNumber%.don" "*_%newFileNumber%.csv"
)
ren "*_%fileNumber%.don" "*_%newFileNumber%.don"
set fileNumber=%fileNumber%-1
set newFileNumber=%newFileNumber%-1
)
This should simply update all the files in the directory to increment by 1 in the file name. If anyone can point out where I'm going wrong I would really appreciate it.
#ECHO OFF
SetLocal EnableDelayedExpansion
:: target directory name in variable for convenience.
SET "targetdir=U:\sourcedir"
:: switch to target directory
pushD "%targetdir%"
:: Start count at 100 so that it is 3 digits long
set cnt=100
dir
for %%A in (*) do set /a cnt+=1
set /A fileNumber = %cnt%
set /A newFileNumber = %cnt%+1
:: echoing last 2 characters (will be digits) of variables
echo %fileNumber:~-2% (%filenumber%)
echo %newFileNumber:~-2% (%newfilenumber%)
:: Assign %%F to values 100+actual descending by 1 to 101
for /l %%F in (%fileNumber%,-1,100) do (
rem note need REM remarks within the loop
REM use !varname! for current value of variable VARNAME
if !newFileNumber:~-2!==90 (
ECHO ren "*_!fileNumber:~-2!.don" "*_!newFileNumber:~-2!.csv"
)
if !newFileNumber:~-2!==60 (
ECHO ren "*_!fileNumber:~-2!.don" "*_!newFileNumber:~-2!.csv"
)
if !newFileNumber:~-2!==30 (
ECHO ren "*_!fileNumber:~-2!.don" "*_!newFileNumber:~-2!.csv"
)
rem Since you've just renamed (eg) _59.don to _60.csv, _59.don is missing
IF EXIST "*_!fileNumber:~-2!.don" ECHO ren "*_!fileNumber:~-2!.don" "*_!newFileNumber:~-2!.don"
set /A fileNumber=fileNumber-1
set /A newFileNumber=newFileNumber-1
)
:: return to original directory
popd
GOTO :EOF
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO REN to REN to actually rename the files.
Unfortunately, you've shown us HOW you've NOT been able to do some operation that's a little vague. We thus need to nut out what you intend to do, which is more work and prone to chasing wild geese.
You don't say what to do with files *_90, so we can't help there.
You appear to want to change *_59.don to *_60.csv, but your rename wants to change *_60.DON the next invocation, so unless the name has been changed from _*60.CSV back to *_60.DON, this isn't going to work.
Note that the basis of this routine is to work with the last two characters of variables. This is to accommodate the leading 0 you say is in your numbering scheme.
It's standard practice to assume that you will exercise any routine against a test directory for verification.
Note that every REN is ECHOed, so it is not EXECUTED, merely reported. Change the ECHO REN to REN to actually execute the command.
Note also that batch is largely case-insensitive. This means you don't have to wear out your SHIFT key unless you want to.
To do math you have to use /A with SET
SET x=1
SET /A x=%x%+1
ECHO %x%
The /A switch specifies that the string to the right of the equal sign
is a numerical expression that is evaluated. The expression evaluator
is pretty simple and supports the following operations, in decreasing
order of precedence:
For nested variables you need to use ! instead of %
SetLocal EnableDelayedExpansion
Setlocal EnableDelayedExpansion
for /f %%G in ("abc") do (
set _demo=%%G & echo !_demo!
)
I'm having an issue with the batch script I wrote below. If I take out the "if" statement, it works, but doesn't print out the %size%, if I leave the "if" statement it gives me an error about "0 was unexpected at this time."
I really don't see any syntax errors here, and if I leave echo on, I see the variables getting set with the proper values. Ultimately I want this to restore files if it detects they're in a bad state, but I'm a little confused as to why the variables don't seem to be working properly.
#echo off
set folder="C:/Somedir/"
set backupfolder="C:/Backupdir/"
set minbytesize=0
for /R "%folder%" %%I in (*) do (
set size=%%~zI
set file=%%~nxI
echo %file% is %size%
if %size% EQU %minbytesize% (
REM do something
)
)
pause
the old delayed expansion pitfall:
#echo off
setlocal enableDelayedExpansion
set "folder=C:/Somedir/"
set "backupfolder=C:/Backupdir/"
set "minbytesize=0"
for /R "%folder%" %%I in (*) do (
set "size=%%~zI"
set "file=%%~nxI"
echo !file! is !size!
if !size! EQU !minbytesize! (
REM do something
)
)
pause
endlocal
more you can find here: ss64.com/nt/delayedexpansion.html
need some quick help. This is a university program, everything is working fine except when I call my :forLoop method to iterate through 100 numbers (1,1,100) starting at 1 going by 1 til 100 and doing the iteration % 5 (i%%5). for some reason I cannot get this to work. appreciate any help or direction.
When I echo %%A it is iterating through all the number perfect. When I echo %result% I get a blank "" (nothing inside)
:forLoop
FOR /L %%A IN (1,1,100) DO (
set /A result=%%A %% 2
echo "%%A"
echo "%result%"
)
Correct code is
:forLoop
setlocal ENABLEDELAYEDEXPANSION
FOR /L %%A IN (1,1,100) DO (
set /A result=%%A %% 5
echo !result! >> results.txt
set /A total=!total!+!result!
echo !total!
)
The problem is that the %result% is substituted when the for is read, meaning that it is no longer a variable when the loop is executed. What you need is delayed variable expansion to be enabled and then use ! instead of %:
setlocal ENABLEDELAYEDEXPANSION
:forLoop
FOR /L %%A IN (1,1,100) DO (
set /A result=%%A %% 5
echo "%%A"
echo !result!
)
This is all explained in the help message you get when you run SET /?:
Delayed environment variable expansion is useful for getting around
the limitations of the current expansion which happens when a line
of text is read, not when it is executed. The following example
demonstrates the problem with immediate variable expansion:
set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "%VAR%" == "after" #echo If you see this, it worked
)
would never display the message, since the %VAR% in BOTH IF statements
is substituted when the first IF statement is read, since it logically
includes the body of the IF, which is a compound statement. So the
IF inside the compound statement is really comparing "before" with
"after" which will never be equal. Similarly, the following example
will not work as expected:
set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%
in that it will NOT build up a list of files in the current directory,
but instead will just set the LIST variable to the last file found.
Again, this is because the %LIST% is expanded just once when the
FOR statement is read, and at that time the LIST variable is empty.
So the actual FOR loop we are executing is:
for %i in (*) do set LIST= %i
which just keeps setting LIST to the last file found.
Delayed environment variable expansion allows you to use a different
character (the exclamation mark) to expand environment variables at
execution time. If delayed variable expansion is enabled, the above
examples could be written as follows to work as intended:
set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "!VAR!" == "after" #echo If you see this, it worked
)
set LIST=
for %i in (*) do set LIST=!LIST! %i
echo %LIST%