windows command line giving error on calculation - variables

I found this nice little tidbit of code here: https://stackoverflow.com/a/5262637/2128987
#echo off
set starttime=%TIME%
set startcsec=%STARTTIME:~9,2%
set startsecs=%STARTTIME:~6,2%
set startmins=%STARTTIME:~3,2%
set starthour=%STARTTIME:~0,2%
set /a starttime=(%starthour%*60*60*100)+(%startmins%*60*100)+(%startsecs%*100)+(%startcsec%)
:TimeThis
robocopy /e /NFL /NDL /NJH /NJS /nc /ns /np folder%rndfolder% %drvltr%:\f%dirnew%\
set endtime=%time%
set endcsec=%endTIME:~9,2%
set endsecs=%endTIME:~6,2%
set endmins=%endTIME:~3,2%
set endhour=%endTIME:~0,2%
if %endhour% LSS %starthour% set /a endhour+=24
set /a endtime=(%endhour%*60*60*100)+(%endmins%*60*100)+(%endsecs%*100)+(%endcsec%)
set /a timetaken= ( %endtime% - %starttime% )
set /a timetakens= %timetaken% / 100
set timetaken=%timetakens%.%timetaken:~-2%
echo.
echo Took: %timetaken% sec.
As a standalone program it works great. I am using it with a robocopy command basically to determine how long it takes to write a file.
I add one extra variable in it because I want to keep the raw seconds for calculation purposes. So I add the extra line set timeraw=%timetaken%:
set /a timetaken= ( %endtime% - %starttime% )
***set timeraw=%timetaken%***
set /a timetakens= %timetaken% / 100
set timetaken=%timetakens%.%timetaken:~-2%
My batch file also uses setlocal enabledelayedexpansion
Well sometimes it does not properly calculate the "starttime" or "endtime". It's keeps it as the raw time in 08:30:22.35 type format and results in the error:
Invalid number. Numeric constants are either decimal (17),hexadecima (0x11), or octal (021)
Well obviously because it contains non-numeric characters like the : character.
My batch file goes in a continuous loop forever as I am using it to read, write, delete files and folders for a specific torture test condition.
Any idea why it would intermittently not calculate the starttime or endtime variables?
edit:
I made some changes to my overall script. I no longer need enabledelayedexpansion, cleaned up some if then statements, and simplified code a little. But I still occasionally get it where the starttime or endtime variables remain as the raw time format of HH:MM:SS.CS and causes error in calculation.

Old question, but there are probably blocks of parentheses and when you change a variable within parentheses then you need to use delayed expansion.
Run this and examine the differences.
#echo off
set a=nothing
if z==z (
set a=b
echo %a%
)
pause
setlocal enabledelayedexpansion
set a=nothing
if z==z (
set a=b
echo !a!
)
pause

Gee - a question nearly a year old, with no answer.
I'll assume that the problem has now been solved, so as a matter of record, I'd conclude that the
"sometimes it does not properly calculate" is because the hour/minute/second/hundredths will contain "08" or "09" which are not octal numbers.
The solution is
set /a startcsec=1%STARTTIME:~9,2% - 100
and repeat with each of the other 3 start time-segments; then repeat again with the end parts.
In addition, it could be that the hour is being presented with 0s suppressed. In this case, I'd suggest
set starttime=0%TIME: =%
set starttime=%startTIME:~-11%
set /a startcsec=1%STARTTIME:~9,2% - 100
where the first line prefixes the time with a '0', and replaces Space with [nothing]
the second selects just the last 11 characters of the result
and the last is the familiar form, using the resultant hh:mm:ss.cc format.
(obviously, the remainder of the substring-and-calculate method needs also to be implemented)

Related

Assigning a variable to the output of a findstr/find combination

I have a log file, that prefixes all lines in it with the date and time. For instance:
2015-02-04 16:11 Error Message: Important Bit Useless Information.
I wish to write a batchfile that when run picks out all the lines from the last hour and then counts how many of these lines contain "Important Bit" and then output this count if it's greater than a given value.
The part I am having difficulty with is basically the main part. I have set up the batchfile, it finds the date, finds the last ten minute period. I cannot then get the file to do the above.
My current command for this is as below, where date and now are assigned to the current date and time:
set count="findstr /G:“%date% %now%” “C:\Documents\File.txt” | find /C "Important Bit""
If %count% geq 5 echo Found %count% lines >> C:\Documents\Output.txt
When I run this, as far as I can tell, nothing happens. I've tried using a FOR command as well, but this still wouldn't work.
Any suggestions are greatly appreciated!
Thanks
Use something like the following:
set /a COUNT=0
for /f %%i in ('findstr /i /c:"Important Bit" test.txt') do (
set /a COUNT=COUNT + 1
)
echo %COUNT%

Variable set in batch file won't show

When I do this in Notepad, the command prompt doesn't show ping %ip% -t -l %package%, but it shows ping %ip% -t -l and doesn't show the package variable.
#echo off
set data=0
set package = -600
IF %data% == 0 (
set /a package= %package% + 1600
#echo ping %ip% -t -l %package%
)
echo %package%
pause
What am I doing wrong?
Batch is sensitive to spaces in a SET statement. SET FLAG = N sets a variable named "FLAGSpace" to a value of "SpaceN"
The set "var=value" syntax ensures that any trailing spaces on the batch line are not included in the value assigned to var.
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var.
So:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set /A data=0
set /A package=-600
IF %data% == 0 (
set /a package=!package!+1600
echo ping %ip% -t -l !package!
)
echo %package%
pause
Noting: The setlocal statement should normally be placed at the start of the code. Your posted code is evidently a snip, since you do not appear to be setting ip.
Spaces are irrelevant in a set /a but even so, removing them fosters a habit
Set /a uses the run-time value, not the parse-time value of var when the syntax set /a var=var+1 is used within a loop, so set /a var=var+1 and set /a var=!var!+1 are equivalent but set /a var=%var%+1 uses the value of var at the time the loop is parsed.
Since echoing is set to off by the initial statement, the leading # on the second echo is redundant.

Batch - set variable error; variable(%)(string)(%%a)(%)?

On the batch script I'm currently working on, I've encountered a bit of a problem.
What I want to happen is to set a variable as itself, but after it to be followed by a percentage mark, a letter, a number from a for /l (#,#,#) loop, then another percentage sign.
My code is currently as follows;
set value1=1
set value2=10
for /l %%a in (%value1%,1,%value2%) do (
set variable1=%variable1%%b%%a%
)
This doesn't give me a value for %variable1% at all, even after looping this 10 times. I've tried adding 'variable1= ' (without apostrophes) to the top, however that gave me the same result. After searching around, I figured that I should try and cancel out the %'s which are before the 'b' and after the 'a' - using %'s in front of them -,and my code ended up like this;
set value1=1
set value2=10
set variable1=
for /l %%a in (%value1%,1,%value2%) do (
set variable1=%variable1%%b%%a%
)
This is the closest I got, however %variable1% would change the value to '%b1%', then '%b2%', then '%b3%', etc. Instead of tiling them up next to each other.
My desired result would be for, by the end of the loop, %variable1% to have a value of; %b1%%b2%%b3%%b4%%b5%%b6%%b7%%b8%%b9%%b10%
Where is my code going wrong? It seems that it should give me my desired output, however quite clearly, it's not.
Thanks in advanced,
Try this:
#echo off
setlocal EnableDelayedExpansion
set value1=1
set value2=10
set variable1=
for /l %%a in (!value1!,1,!value2!) do (
set percent=%%
set variable1=!variable1!!percent!b%%a!percent!
)
echo !variable1!
You will have to add setlocal EnableDelayedExpansion as this will helps to expand the variable at execution time rather than at parse time.

Batch IF statement variable inside another variable

I'm having a problem with a framework for a batch game I'm trying to create. I want to check if a variable is something other than a blank space. However, which variable I'm trying to check is in itself defined by two variables. For example:
if not %px%xplayerlocation%y%yplayerlocation%%==%blank% goto wherever
As you can see, the variable to be checked is determined by the values of %xplayerlocation% and %yplayerlocation%. To my knowledge, only the outermost %% signs are being read as being a variable and the inner ones are being read as literal percent signs. Does anyone know a way around this problem? I'll give any additional information if anyone needs it. Thanks.
#ECHO OFF
SETLOCAL
SET "blank= "
SET xplayerlocation=3
SET yplayerlocation=4
ECHO test with blank================
SET px3y4=%blank%
CALL SET varval=%%px%xplayerlocation%y%yplayerlocation%%%
if not "%varval%"=="%blank%" ECHO goto wherever - NOT blank
ECHO test with "Q"================
SET px3y4=Q
CALL SET varval=%%px%xplayerlocation%y%yplayerlocation%%%
if not "%varval%"=="%blank%" ECHO goto wherever - NOT blank
GOTO :EOF
This should get you out of trouble.
You have recognized the source of the problem, but your description of the behavior is incorrect. The parser will attempt to expand variables named px and y, and it will convert the final %% into %.
The Magoo solution will work, but using CALL is quite slow. That may not be a problem for many small scripts, but for a batch game it can kill performance.
You want delayed expansion. Include setlocal enableDelayedExpansion near the beginning of your script. Then use the following:
if not !px%xplayerlocation%y%yplayerlocation%!==%blank% goto wherever
Normal %var% expansion occurs early at parse time, and !var! expansion occurs late at execution time, so you get the proper result.
The above will not work if the value of %blank% is a space. The simplest solution would be to use delayed expansion for !blank! as well.
You might find yourself in a situation where the coordinate values need to be set and expanded within the same block of code, like in a FOR loop or IF statement:
setlocal enableDelayedExpansion
...
REM This does not work
for ... in (...) do (
...
set /a "xPlayerLocation+=xChange, yPlayerLocation+=yChange"
if not !px%xplayerlocation%y%yplayerlocation%!==!blank! REM doSomething
...
)
The above will not work because %var% expansion occurs at parse time, and the entire parenthesized block of code is parsed before any code is executed. So the expanded value is constant - it will expand to the value that existed before the loop started.
The solution is to transfer the coordinate values to FOR variables using delayed expansion:
setlocal enableDelayedExpansion
...
REM This works
for ... in (...) do (
...
set /a "xPlayerLocation+=xChange, yPlayerLocation+=yChange"
for %%X in (!xPlayerLocation!) do for %%Y in (!yPlayerLocation!) do (
if not !px%%X%y%%Y!==%blank% REM doSomething
)
...
)
or
setlocal enableDelayedExpansion
...
REM This also works
for ... in (...) do (
...
set /a "xPlayerLocation+=xChange, yPlayerLocation+=yChange"
for /f "tokens=1,2" %%X in ("!xPlayerLocation! !yPlayerLocation!") do (
if not !px%%X%y%%Y!==%blank% REM doSomething
)
...
)
If you are serious about developing a high quality game using batch, then you may be interested in studying the techniques I used in developing SNAKE.BAT - an arcade style game using only native batch commands. The beginning of the post is a bunch of code, but afterwards I describe a number of techniques I used for improving performance. It is advanced stuff, so don't try to absorb everything at once. Absorb what you can, and then revisit the post later on after you gain more experience.

How to create nested variables in batch?

I am trying to get nested variables in my batch game i am creating.
I want it so that it will choose a random variable and change it to X, but if it is already chosen, it should go back and choose a different number.
set 1=a
set 2=b
set 3=c
set 4=d
set 5=e
those were the variables, here is the code
setlocal enabledelayedexpansion
:eliminator
set /a eliminate=(%random * 5) / 32767 + 1
if %%eliminate%%==X goto eliminator
echo The letter !!eliminate!! was chosen
timeout 5
set %%eliminate%%=X
goto eliminator
Now, the thing is, when I try to echo it, it writes the name of the variable instead of the value. Also, variables that have already been chosen are being chosen again. Any way I could fix this? Thanks.
try this:
#echo off&setlocal
set "var1=a"
set "var2=b"
set "var3=c"
set "var4=d"
set "var5=e"
:loop
set /a rd=%random%%%5+1
if defined var%rd% call echo %%var%rd%%%
set "var%rd%="
set "var" >nul 2>&1 && goto:loop
..output (may vary):
d
a
c
b
e
Your posted code is missing the closing % around random - it should read %random%.
Your formula for a random number between 1 and 5 is more complicated than need be. I would use:
set /a eliminate=%random% %% 5 + 1
To expand a "nested variable" you need !%eliminate%!
But I would completely rewrite your algorithm. I think the following does what you want:
#echo off
setlocal enableDelayedExpansion
set "chars=abcde"
set charCnt=5
:loop
set /a "pos=%random% %% charCnt, pos2=pos+1, charCnt-=1"
set "letter=!chars:~%pos%,1!"
echo The letter %letter% was chosen
set "chars=!chars:~0,%pos%!!chars:~%pos2%!"
if defined chars goto loop
The script is optimized to always pick a valid unused letter on each iteration.