Loop the command continuously (without pausing) for "X" seconds - loops

Currently I am working on a batch file to execute a command continuously for X no. of seconds, and after elapse of X, I wish to redirect it using goto function.
This is the closest I have got to what I intend the code to do.
:MainMenu
set yourno=
set /p yourno=Input your number:
set /p looptime=Input time:
goto PerformCalc
:PerformCalc
set /a yourno= %yourno%+1
timeout 1
set /a looptime=%looptime%-1
goto CheckLoop
:CheckLoop
if %looptime% equ 0 goto FinishScreen
goto PerformCalc
:FinishScreen
echo Congratulations Your no. is %yourno%
echo Operations completed in %looptime% seconds
pause
Now the problem with the above code is if I set the loop time for 10 seconds, it will perform only 10 operations. But that is not something I intend to do. I realize that I have inputted timeout 1 in my code and reducing it by 1 everytime 1 second passes. However this is because I am unable to find a way to continuously loop the code for 10 seconds, without using timeout 1 thus pausing it to perform only 10 operations.
If you still do not get what I mean, here is the logical flow the code should perform (say for eg. the user inputs looptime as 10 seconds
For Time=10seconds
Do {set /a yourno= %yourno%+1 continuously}
After Time of 10 seconds has elapsed redirect to :FinishScreen
Thankyou for your help.

#echo off
setlocal
rem Get end time
set seconds=10
for /F "tokens=1-4 delims=:.," %%a in ("%time: =0%") do set /A "endTime=1%%a%%b%%c%%d+seconds*100"
echo Start: %time%
echo Working %seconds% seconds, please wait...
set yourNo=0
:loop
set /A yourNo+=1
rem Check if end time had been reached
for /F "tokens=1-4 delims=:.," %%a in ("%time: =0%") do if 1%%a%%b%%c%%d lss %endTime% goto loop
echo End: %time%
echo This program could complete %yourNo% loops in 10 seconds
This method may fail if the processing time pass over midnight, but a simple adjustment can solve this point, if needed...

Related

Delayed Expansion Inside Loop with Arithmetic Operations on Time Values

I am relatively new to batch files, and I have been trying to get the following timing routine (inspired from Arithmetic operations with HH:MM:SS times in batch file) to work:
set "startTime=%time: =0%"
#rem Removing milliseconds information
set startTime=%startTime:~0,-3%
setlocal EnableDelayedExpansion
for %%i in (1 2 3 4 5) do (
timeout /T 3 /NOBREAK
set endTime=!time: =0!
set endTime=!endTime:~0,-3!
set /A "ss=(((1%endTime::=-100)*60+1%-100)-(((1%startTime::=-100)*60+1%-100)"
set /A "hh=ss/3600+100,ss%%=3600,mm=ss/60+100,ss=ss%%60+100"
#rem Get format in HH:MM:SS (maybe H:MM:SS after midnight.. not tested yet)
echo Start time: %startTime%
echo End time: !endTime!
#rem Issue here: Always get the same output despite delayedExpansion active
echo Diff time: !ss!
echo.
#rem Issue here: Not getting expected values
echo Elapsed time: !hh:~1!:!mm:~1!:!ss:~1!...
echo.
)
endlocal
I am not quite sure why the output value for the time difference is always the same despite the delayed expansion. Also, the formatted time does not give me the correct values.
Thanks for your help!
First, thanks for the helpful comments which helped me find a solution to my question. In case it might help someone else, I am posting the solution here.
As mentioned in the comments, the key was to determine the formatting used on my operating system.
The code that works for me is below, inspired from https://www.py4u.net/discuss/2286184:
#rem Check that the format of %TIME% is HH:MM:SS.CS for example 23:59:59.99
echo "%TIME%"
set STARTTIME=%TIME%
#rem convert start time to centiseconds
set /A STARTTIME=(1%STARTTIME:~0,2%-100)*360000 + (1%STARTTIME:~3,2%-100)*6000 + (1%STARTTIME:~6,2%-100)*100 + (1%STARTTIME:~9,2%-100)
setlocal EnableDelayedExpansion
for %%i in (1 2 3 4 5) do (
timeout /T 3 /NOBREAK
set ENDTIME=!TIME!
#rem convert ENDTIME to centiseconds
#rem I found that double-quotes with set /A and numbers are needed inside the for loop
set /A "ENDTIME=(1!ENDTIME:~0,2!-100)*360000 + (1!ENDTIME:~3,2!-100)*6000 + (1!ENDTIME:~6,2!-100)*100 + (1!ENDTIME:~9,2!-100)"
#rem calculating the duratyion is easy
set /A DURATION=!ENDTIME!-%STARTTIME%
#rem Adjust for cases where timings over multiple days
if !ENDTIME! LSS %STARTTIME% set set /A DURATION=%STARTTIME%-!ENDTIME!
#rem now break the centiseconds down to hours, minutes, seconds and the remaining centiseconds
set /A "DURATIONH=!DURATION! / 360000"
set /A "DURATIONM=(!DURATION! - !DURATIONH!*360000) / 6000"
set /A "DURATIONS=(!DURATION! - !DURATIONH!*360000 - !DURATIONM!*6000) / 100"
set /A "DURATIONHS=(!DURATION! - !DURATIONH!*360000 - !DURATIONM!*6000 - !DURATIONS!*100)"
#rem Enforce double-digit format
if !DURATIONH! LSS 10 set DURATIONH=0!DURATIONH!
if !DURATIONM! LSS 10 set DURATIONM=0!DURATIONM!
if !DURATIONS! LSS 10 set DURATIONS=0!DURATIONS!
if !DURATIONHS! LSS 10 set DURATIONHS=0!DURATIONHS!
#rem Outputing timings
echo STARTTIME: %STARTTIME% centiseconds
echo ENDTIME: !ENDTIME! centiseconds
echo DURATION: !DURATION! in centiseconds
echo Elapsed time: !DURATIONH!:!DURATIONM!:!DURATIONS!.!DURATIONHS!
)
endlocal

Comparing User input variable to time command in batch

I'm trying to make a batch file that'll run in the background and shut my computer off when the regional time corresponds to a time I've set so that I can fix my sleep schedule.
However, I'm running into issues testing how to compare the current time to the time I've set as a variable.
I believe that it's due to the format that is returned by the time command and the format I entered not being the same.
I would like to enter a time in the 12-hour format and the computer shuts down at the designated time. But the time command returns a 24-hour format string unless paired with the /t switch.
This is what I currently have as test code that returns a printed line instead of shutting down my computer:
#echo off
set /p shutdownTime=What time would you like to shut down the computer?
:begin
set time=time /t
if "%time%" EQU "%shutdowmTime%" echo Time Confirmed
goto begin
I know that instead of an if statement in a loop I could probably do a for or while loop, but I'm honestly trying to keep it as simple as I can for my nocturnal smooth brain that woke up about 3 hours ago.
Any help is appreciated. Thank you.
Try this:
#echo off
FOR /F "tokens=* USEBACKQ" %%F IN (`time /t`) DO (
SET var=%%F
)
echo %var%
pause
will output 12hr time
#echo off
:resettime
echo make sure to Use caps for AM/PM and no spaces
set /p stime=What time would you like me to shutdown your computer?[example 03:45(AM/PM)]:
cls
echo your computer will shutdown at %stime%
:R
set /p p=would you like to change this time [y/n]:
if %p%==y goto resettime
if %p%==n goto loop
if not %p%==y goto R
if not %p%==n goto R
:loop
FOR /F "tokens=* USEBACKQ" %%F IN (`time /t`) DO (
SET var=%%F
)
set var=%var: =%
if %stime%==%var% goto endloop
goto loop
:endloop
shutdown /s
:a
set /p prompt=Would you like to abort shutdown [y/n]:
if %prompt%==y goto s
if not %prompt%==y goto a
:s
shutdown /a
I also quickly made the program described in your question. Its a bit buggy but it works.

I need to press a specific key and have my script " GO TO" another part in the script

I have a batch script that I desperately need help with. I use a batch script to grab files from folders and move them. The script sweeps the folders every 30 sec but you can "press a key to continue" also. I need to change it so I can press a specific key, doesn't matter what key, and have it GO TO the top location of my script to reset.
Below is a striped down version of what I currently have.
#echo off
set /p username=ENTER LOGIN:
echo.
:pc
echo 1 -- Flats
echo 2 -- Simple Tabletop
set /P rmFunc="Enter a choice: "
for %%I in (1 x) do if #%rmFunc%==#%%I goto run%%I
:run1
set pc=300
goto begin
:run2
set pc=400
goto begin
:begin
set studio=TT
set computer=Handbag_1
set setnumber=
set studiosetnumber=%studio%_%setnumber%
set delay_swch=5
set delay_loop=30
:bottom
echo logged in as: %username%
timeout /t %delay_loop%
GOTO BOTTOM
It is not possible to determine what key was pressed when using TIMEOUT, so that command is of no help.
You could use the CHOICE command with the /T (timeout) and /D (default) options instead. You can no longer simply press any key. Instead you can only press one key to restart, and another specific key to continue, or wait till the default value (continue) is returned. The biggest drawback is it no longer has a visual countdown.
echo Press C to Continue, or R to Restart
choice /c cr /d c /t 30 /n /m "The process will automatically continue in 30 seconds "
if errorlevel 2 goto pc
goto bottom
You could display a countdown timer by adding a third undocumented default option and setting the timeout to 1 second. If the default is returned, then it decrements the counter. Once the counter reaches 0 then the desired time has elapsed and you treat it as Continue.
I use the SET /P trick to display the prompt with a without a newline. I end with a carriage return so that the next prompt displays from the beginning of the same line.
The countdown timing will be a bit off, but it should be plenty good enough.
The carriage return variable must be defined and delayed expansion must be enabled near the top (before any loop label).
:: Define CR to hold a carriage return (0x0D)
for /f %%A in ('copy /Z "%~dpf0" nul') do set "CR=%%A"
:: Delayed expansion must be enabled to use the CR variable
setlocal enableDelayedExpansion
The timer code then becomes
set wait=15
:waitLoop
<nul set /p ="Press C to Continue, or R to Restart. Auto continue in %wait% seconds. !CR!"
choice /c 0cr /t 1 /d 0 >nul
if errorlevel 3 echo(&goto pc
if errorlevel 2 echo(&goto bottom
set /a wait-=1
if %wait% equ 0 echo(&goto bottom
goto :waitLoop
timeout does not return errorlevel if interrupted, so perhaps one way to solve this is to time timeout
#ECHO Off
SETLOCAL
SET /a "starttime=1%time:~-5,2%%time:~-2%"
timeout /t 30
SET /a "endtime=1%time:~-5,2%%time:~-2%"
IF %endtime% lss %starttime% SET /a endtime +=6000
SET /a elapsed=endtime - starttime
ECHO %elapsed%
GOTO :EOF
elapsed should contain the resultant time in tens-of-milliseconds. It's unlikely to be exactly 3000 for a 'no keypress' situation, but perhaps if %elapsed% gtr 2980 echo no keypress would suffice.
Note that I use a time format of hh:mm:ss.hh so if yours is different, you'd need to adjust the time substringing.
Since the target here is a timeout of about 30 seconds, the calculations can be performed on the seconds digits only. The values are accumulated as 1ss(.)hh which ensures that there is not a leading zero so set /a will not attempt to enter octal mode. Since it's entirely possible that the end time will be in the next minute, the adding of 6000 compensates by adding-in the minute (6000 tens-of-milliseconds)
Since it seems to be necessary to build the entire batch,
#echo off
set /p username=ENTER LOGIN:
echo.
:pc
echo 1 -- Flats
echo 2 -- Simple Tabletop
set /P rmFunc="Enter a choice: "
:
for %%I in (1 x) do if #%rmFunc%==#%%I goto run%%I
:run1
set pc=300
goto begin
:run2
set pc=400
goto begin
:begin
set studio=TT
set computer=Handbag_1
set setnumber=
set studiosetnumber=%studio%_%setnumber%
set delay_swch=5
set delay_loop=30
:bottom
echo logged in as: %username%
SET /a "starttime=1%time:~-5,2%%time:~-2%"
timeout /t %delay_loop%
SET /a "endtime=1%time:~-5,2%%time:~-2%"
IF %endtime% lss %starttime% SET /a endtime +=6000
SET /a elapsed=endtime - starttime
if %elapsed% leq 2980 goto ???
GOTO BOTTOM
And - well there I'd have to leave it. You are setting studio and setnumber to constants within your code. Are these somehow related to "Process Class?" If you want to re-enter this data, then you'd need ??? above to be begin - but you'd need to set /p those values (which you haven't shown.) As for the file sweep - there's nowhere in your code that shows this filesweep happening. The modifications I have indicated will allow you to press any key to interrupt the 30-second bottom loop and re-enter the data.

Milliseconds (!) wait in Batch using no externals?

I have searched intensively but have only found wait-tips in batch files in seconds units (the ping approach i.e.).
Since I have a need to wait in between two commands only for something like 10-100 milliseconds, that does not work for me unfortunately.
The wait-time needs not to be "super accurate". In my case, does not make a big difference if it's 10ms or 12/15ms, but it should be able to distinguish between 10 and, say 20.
I wonder if there is a solution, and if in any way possible, using just the windows "on board" commands / tricks as I want to have just the batch for ease of "installation" when using later on another machine.
#echo off
echo Time before: %time%
echo Wait %1 centiseconds (or more)
call :wait %1
echo Time after: %time%
goto :EOF
:wait centiseconds
for /F "tokens=3,4 delims=:." %%a in ("%time%") do set /A sec=1%%a, msec=1%%b+%1
if %msec% gtr 199 set /A sec+=1, msec-=100
set lim=%sec%%msec%
:waitHere
for /F "tokens=3,4 delims=:." %%a in ("%time%") do if 1%%a1%%b lss %lim% goto waitHere
exit /B
The minimum precise wait time entirely depends on the speed of the computer. For example, in my case a wait time less than 5 centiseconds always waits for more time. If I use a wait time from 5 centiseconds on, the timing is precise.
EDIT: I slightly modified the program in order to make it more precise with small wait times, it is now precise in my computer from 3 centiseconds on!
You must note that the minimum precise wait time also depends on the size of the Batch file; if the file is large, the minimum precise time increases...
You can use the %time% variable and calculate the difference.
In pseudo code it looks like this.
set startTime=%time%
:wait
set now=%time%
if now-startTime < waitTime goto wait
Btw externally programs will not work here, as the loading/starting time is not predictable and can be much longer as your waittime.
this might do, what you want:
#echo off
echo %time%
for /L %%i in (1,1,50) do ( echo %time% )>nul
echo %time%
for example three consecutive runs:
C:\>t
12:15:20,74
12:15:20,75
C:\>t
12:15:21,22
12:15:21,22
C:\>t
12:15:21,69
12:15:21,71
As you see, the first run gives you "about" 10ms, the second run gives you "about" 0ms, the third one gives you "about" 20ms.
Nothing reliable...
btw: if you replace echo %time% with echo time it's getting worse...

Creating a geometrically decaying pause loop

So I am working on creating a batch file game analogious to a "Memory" game. (ie where the player is presented a list of objects for a short time, then asked to repeat the pattern)
My problem comes in how to decrease the time the pattern is exposed to the player as the round # increases.
Here is my current code:
#echo off
set /a y=50
set /a x=1000
:foo
set /a y=%y% + %y%
set /a x= %x% - %y%
echo %y%
echo %x%
ping -n 10 -w %x% 127.0.0.1 > nul
goto foo
When run, the above code does present x and y values that change as expected, however the wait time is always the same. Why is this and how can I fix it?
Thank you for your time.
Firstly why dont you use sleep? It would work fine (type sleep /? for more info)
However, here is another way of doing this with for /l loops
#echo off
setlocal enabledelayedexpansion
set score=0
title Memory Test : Current Score = !score!
for /l %%a in (0,1,20) do (
Rem In the above sequence, increase 20 to the amount of times you want the test to be performed
set number[%%a] = !random!!random!
echo Number: !number[%%a]!
set /a wait=21-%%a
set /a wait=!wait!*1000/4
sleep -m !wait!
cls
set /p "input=What was the last number youy saw? "
if !number[%%a]! equ "!input!" (
set /a score=!score!+1
Echo Correct !
title Memory Test : Current Score = !score!
)else(
Echo Incorrect! Coreect Answer = !number[%%a]!
)
)
echo Calculating score...
pause
cls
echo.
if %score% leq 14 set msg="Nice Try! But you can do better!"
if %score% geq 15 set msg="Good Job! Your on your way to the top!"
if %score% equ 20 set msg="Your So Close! Almost a perfect socre!"
if %score% equ 21 set msg="You got a perfect score! Woderful!"
Echo %score%/21 : %msg%
echo.
pause
And that should work fine. Note you can change how long the test goes for, but for the first game they'll have a bit more then 5 seconds to study the question, and in the last round a quarter of a second!
Mona
In order for the ping/wait trick to work, the ip address must not exist. 127.0.0.1 is your own computer, so it has no opportunity to timeout since the ping response is successful and immediate.
Instead, choose an ip address that doesn't exist. E.g. 10.20.30.40 (assuming that doesn't exist.)
You can adjust the 10 in this to give approximately second resolution. Is that sufficient for your code?
ping -n 10 127.0.0.1 > nul
This is another option for later windows.
timeout /t 10 >nul

Resources