Limit a batch file to only be able to run after 20 seconds after last run - batch-file

I need to make a batch file that calls a URL (without opening a browser), but only after 20 seconds since previous run. If it's run sooner than 20 seconds, the script does nothing and closes. How would I go about doing this?

If your batchfile waits 20 seconds before closing, and you can only have one instance of it running at a time, then the problem is solved.
Use a technique like this or this to make your batch file exit ,without doing anything else, if it is already running.
Then, if the batchfile does not detect another instance running, Use the timeout command at the end of the batchfile to wait 20 seconds.
timeout /t 20

#montewhizdoh: if you add a timeout at the end of the batch file, it means you have to wait for 20 seconds before the batch actually returns, which may not be desirable, especially if the operations it performs are supposed to occur quickly.
#seventy70: by recording the current time in a separate file, you can ensure that the batch will exit without doing anything you don't want it to, unless a certain number of seconds has elapsed. The following code achieves this:
#echo off
Setlocal EnableDelayedExpansion
set lastTime=86500
if NOT EXIST lasttime.txt goto :nextStep
for /f "delims=;" %%i in (lasttime.txt) do (
set lastTime=%%i
)
set /A lastTime=(%lastTime:~0,2%*3600) + (%lastTime:~3,2%*60) + (%lastTime:~6,2%)
:nextStep
set currTime=%TIME%
set /A currTime=(%currTime:~0,2%*3600) + (%currTime:~3,2%*60) + (%currTime:~6,2%)
:: required check in case we run the batch file right before and right after midnight
if %currTime% LSS %lastTime% (
set /A spanTime=%lastTime%-%currTime%
) else (
set /A spanTime=%currTime%-%lastTime%
)
if %spanTime% LSS 20 (
echo Only %spantime% have passed since the last run
goto :eof
)
:: ************************************
:: DO ACTUAL STUFF HERE
:: ************************************
if exist lasttime.txt del lasttime.txt
echo %time%>>lasttime.txt
endlocal
So every time the batch is allowed to run, it records the current time in a file. The next time around, it reads the file, extracts the time from it and compares it with the current time. If less than 20 seconds have elapsed, the batch exits. If more than 20 seconds have passed, the actual operations can be executed and at the end, the current time is recorded again in the control file for use next time around.

Related

Loop batch file for X minutes?

I am very new to batch files, having mostly coded in Matlab for years. I would simply like to loop some code I have written for a set number of minutes. In pseudocode:
While elapsedTime<timeLimit
Run Code
How do I declare the variables elapsedTime (which would be a time counter that runs throughout the While loop) and timeLimit (just a value in seconds)?
If you are using batch you could do this:
#echo off
set /p min=Set minutes:
set /a sec=%min% * 60
timeout %sec%
Calculating with time is difficult in batch (not impossible, just difficult).
Here is another approach: creating a dummy file, start an additional (independent) process which waits a certain time and then deletes the file.
The original process can loop until the file disappears:
#echo off
break> timer.tmp
start /min cmd /c "timeout 5 & del timer.tmp"
:loop
echo waiting...
timeout 1 >nul
if exist timer.tmp goto :loop
echo done waiting.
Just adapt the timeout to the desired time (5 seconds in my example)

Working around 32 window limit in MinGW (Windows batch files)

I'm a computational biologist and I'm trying to run large batches of similar code with a single command, but my implementation has hit a brick wall.
I'm using the NEURON simulation environment, which uses MinGW for its Windows interface, which is where my research has shown my problem arises.
Currently, I am using a batch file to run all of these similar pieces of code, to iterate across the "collection" subfolders:
#echo off
for /D %%a in ("%cd%\all_cells\cell_*.*") do cd "%%a\sim1\" & START neuron sim.hoc
The problem arises when I have more than 32 subfolders; the additional instances won't run and will error with a "console device allocation failure: too many consoles" error.
My research has shown me that this is a known problem with Cygwin/MinGW.
However, working around this manually (ensuring that there is no more than 32 "collection" folders) is extremely time consuming when I am now dealing with hundreds of instances (each refers to a simulated cell and I want to gather statistics on hundreds of them), so I am trying to find a solution.
That said, I am terrible at writing batch files (I'm a terrible programmer who is used to scientific languages) and I can't figure out how to code around this.
It would be great if someone could help me either find a way around the 32 limit, or failing that, help me write a batch file that would do this:
-iterate over up to 32 folders
-wait for the instances to finish
-do it again for the next 32, until I reach the end of the folder.
I have tried using the /wait command to do them one at a time, but it still opens all 32. (And this wouldn't be ideal as I'd like to use all 16 cores I have.
The following is adapted from https://stackoverflow.com/a/11715437/1012053, which shows how to run any number of processes while limiting the total number run simultaneously in parallel. See that post for some explanation, though the code below is fairly well documented with comments.
I've eliminated the /O option and the code to work with PSEXEC from the original script.
The script below runs everything in one window - the output of each process is captured to a temporary lock file, and when finished, the full output of each process is typed to the screen, without any interleaving of process output. The start and end times of each process are also displayed. Of course you can redirect the output of the master script if you want to capture everything to a single file.
I've limited the total number of parallel processes to 16 - of course you can easily modify that limit.
The code will not work as written if any of your folder paths include the ! character. This could be fixed with a bit of extra code.
Other than that, the code should work, provided I haven't made any silly mistakes. I did not test this script, although the script it was derived from has been thoroughly tested.
#echo off
setlocal enableDelayedExpansion
:: Define the maximum number of parallel processes to run.
set "maxProc=16"
:: Get a unique base lock name for this particular instantiation.
:: Incorporate a timestamp from WMIC if possible, but don't fail if
:: WMIC not available. Also incorporate a random number.
set "lock="
for /f "skip=1 delims=-+ " %%T in ('2^>nul wmic os get localdatetime') do (
set "lock=%%T"
goto :break
)
:break
set "lock=%temp%\lock%lock%_%random%_"
:: Initialize the counters
set /a "startCount=0, endCount=0"
:: Clear any existing end flags
for /l %%N in (1 1 %maxProc%) do set "endProc%%N="
:: Launch the commands in a loop
set launch=1
for /D %%A in ("%cd%\all_cells\cell_*.*") do (
if !startCount! lss %maxProc% (
set /a "startCount+=1, nextProc=startCount"
) else (
call :wait
)
set "cmd!nextProc!=%%A"
echo -------------------------------------------------------------------------------
echo !time! - proc!nextProc!: starting %%A
2>nul del %lock%!nextProc!
cd "%%A\sim1\"
%= Redirect the output to the lock file and execute the command. The CMD process =%
%= will maintain an exclusive lock on the lock file until the process ends. =%
start /b "" cmd /c 1^>"%lock%!nextProc!" 2^>^&1 neuron sim.hoc
)
set "launch="
:wait
:: Wait for procs to finish in a loop
:: If still launching then return as soon as a proc ends
:: else wait for all procs to finish
:: redirect stderr to null to suppress any error message if redirection
:: within the loop fails.
for /l %%N in (1 1 %startCount%) do 2>nul (
%= Redirect an unused file handle to the lock file. If the process is =%
%= still running then redirection will fail and the IF body will not run =%
if not defined endProc%%N if exist "%lock%%%N" 9>>"%lock%%%N" (
%= Made it inside the IF body so the process must have finished =%
echo ===============================================================================
echo !time! - proc%%N: finished !cmd%%N!
type "%lock%%%N"
if defined launch (
set nextProc=%%N
exit /b
)
set /a "endCount+=1, endProc%%N=1"
)
)
if %endCount% lss %startCount% (
timeout 1 /nobreak >nul
goto :wait
)
2>nul del %lock%*
echo ===============================================================================
echo Thats all folks^^!
You could install screen or tmux in cygwin.
Then you can start all neuron instances in a screen/tmux session.
They will not open a new window, so there is no limit anymore.

Batch file timed reminder

I'm trying to get a .bat file to run a reminder popup do to restrictions on my work PC (Windows 7 OS). I am unable to use windows task scheduler due to these restrictions so I need the time check to run inside the batch file itself.
Currently, I have the following:
#echo off
:check
if "%time%"=="09:51:00.00"
msg user42 Test Reminder
Timeout /t 20 /nobreak
GOTO :Check
The issue seems to be with the "if" in the third line. as the rest of the code works with this line removed.
Any advice would be much appreciated.
We would need to manipulate your time variable to make this work as expected, but we don't really want to modify system or user environment variables. So we create our own.
First we make sure the time hour value always has 2 digits by replacing whitespace with 0 as only single digit time (1,2,3..9) will have a leading space. then we remove the : to make it a single matchable numeric value, then we simply do a match to see if the time is greater than or equal to 0951 (09:51 am) and if it is, we check if it is less than 0952 (09:52 am) meaning time has to be 09:51 any second and not 09:52 or larger.
Now we run the script every 50 seconds which will fall inside of each minute regardless, if we left it at 20 seconds, it would alert 2 or 3 times.
#echo off
:check
set mytime=%time: =0%
set mytime=%mytime::=%
if "%mytime:~0,4%" GEQ "0951" if "%mytime:~0,4%" LSS "0952" msg user42 Test Reminder
Timeout /t 50 /nobreak>nul
GOTO :Check

Batch -- How do I execute multiple programs that open (and close) one after another in time intervals as a cycle?

I hope that makes sense. I want to create a batch file or anything similar that will cycle through a few Processing applications for a presentation. Is there a way I can do this that will execute an application by time intervals, close before executing the next one, and then cycle back to the first application?
Certainly.
#ECHO OFF
SETLOCAL
:loop
FOR %%i IN ("process1.exe 20" "process2.exe 30" "process3.exe 10") DO CALL :cycle %%~i
GOTO loop
:cycle
START %1
timeout /t %2 >nul
TASKKILL /im %1 >nul
GOTO :eof
runs process1 for 20 sec, process2 for 30 - Got the pattern? The processes are terminated unceremoniously.
Press control-C and reply Y to terminate - will leave the last process invoked running.
Addendum:
TASKKILL knows nothing about "paths" - only the executable name.
hence, on the line after after the setlocal add
set path=C:\Users\MyName\Documents\School\Processing\Sketch_8\application.windows32;%path%
and specify the executable only in the FOR statement.
If there's more than one directoryname involved, just string them together with ; separators and ;%path% at the end.
Windows picks up the executable from the path by looking first in the current directory, then each directory on the path in turn until it finds the required executable. Adding the extra directories occurs only for the time this batch is running, and applies only to the batch's instance - it's not transmitted to any other process.

Run DOS Command for a Time Limit

I want to perform the following operations.
Read 1 word at a time from an input file consisting of many words.
Pass this word as an argument to another command line based application.
Run that application for a fixed amount of time, say 10 seconds.
Abort the execution of the application if it is still running after 10 seconds and go back, pick the next word from the input file and repeat steps 1 to 3.
Here is what I have written though it does not achieve exactly what I want it to:
#echo off
for /f %%i in ('type input.txt') do call:Routine %%i
:Routine
set app="myApp.exe"
set limit=60
%app% %1
goto Delay
:Delay
ping localhost -n %limit% > nul
The above script will introduce the delay after the execution of myApp has completed. However, I want it to run myApp.exe for not more than 10 seconds, if it does, then abort the application using taskkill and move on to the next word from the input file.
I searched for a solution online and came across this:
http://www.tech-archive.net/Archive/WinXP/microsoft.public.windowsxp.general/2006-04/msg03609.html
Though it does not answer my query exactly, I would like to make my code do something similar.
Thanks.
The logic in the linked code looks flawed: It either launches 3 download commands, or it delays ~59 seconds and attempts to kill all download commands, but it never does both. The TASKKILL command arguments are not correct - the imagename belongs after the /IM parameter.
In your code, you are not going to kill your task without the TASKKILL command!
You must GOTO :EOF or EXIT /B after your loop finishes, otherwise the code will fall through and execute the subroutine without using CALL. But there really is no need to use a subroutine at all.
You only need to initialize your variables once.
No need to execute a command in your IN() clause. FOR /F has a variation that can read the text file directly. Type HELP FOR from the command line and read the documentation carefully.
PING has roughly a 1 second delay between each echo request. So a count of 11 will yield a delay of roughly 10 seconds.
EDIT - originally forgot the critical START command to start the app in its own process
#echo off
set app="myApp.exe"
set limit=11
for /f %%i in (input.txt) do (
start "" %app% %%i
ping localhost -n %limit% > nul
taskkill /im %app% /f
)

Resources