Self Updating Continuously Running Batch

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Samir
Posts: 384
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Self Updating Continuously Running Batch

#1 Post by Samir » 22 May 2020 18:06

I'm sure some of you have one of these running, but I'm having trouble figuring out the best way to implement the 'updating' method.

I have a batch that I execute that loops back it its beginning again when complete so it can run again. Now the problem is that if this batch is running and I update it, the running batch will stop running. This is obvious since the file does get changed when it is saved. Fair enough.

The various methods I found in this stackoverflow seem good for a single time execution, but won't work if the batch is needing to update itself at each loop:
https://stackoverflow.com/questions/171 ... elf-safely

The ideas I've come up with so far:
  • Copy the original batch to a temporary batch and execute that batch. Include a check that if the batch is updated, copy it to another temporary one and execute that batch. Repeat, except overwrite the original temp copy if the batch is updated again. This copies the original batch to 2x temp copies and executes those as needed.
  • At the end of the original batch, have the batch run a 'cmd /c copy "batch.bat" "%0" & %0' to copy a new copy of batch and then execute the new batch, effectively looping to the beginning. I'm also wondering if 'start' would be better to use versus 'cmd /c'.
And that's it. :( I know there has to be an elegant way to do this, so I'm ready to hear any ideas. Thank you in advance. 8)

Samir
Posts: 384
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: Self Updating Continuously Running Batch

#2 Post by Samir » 23 May 2020 02:01

So after thinking about this for a bit it seems like this might be the best way:
  • if the batch started is the original, copy the file to %temp% and execute it there.
  • at the end of the batch, copy the file from the original to %temp% again if orig is newer and execute the %temp% copy again. This will be the loop.
This should allow the original to be updated at any time and it should be updated before being run next if there is an update. And the original batch should effectively keep looping, although it is actually just executing itself each time. I remember using this method to loop a batch back in the DOS 3.3 days, but I don't know how differently it would work in the modern command prompt. Any insights or ideas before I start coding all this up?

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Self Updating Continuously Running Batch

#3 Post by penpen » 23 May 2020 05:17

Samir wrote:This is obvious since the file does get changed when it is saved.
If you overwrite your batch file, then the file pointer of the running file doesn't change.
So if your new file has a valid command at that fileposition, then it will run without issues (except that the resulting algorithm may not be what you would expect).
But i think the easiest way is by exchanging the batch file as a last task, and then jump to a valid label.

Simple example:

Code: Select all

:mainEntryPoint
@echo off
setlocal enableExtensions disableDelayedExpansion
set "counter=0"
if %counter% equ 10 goto :eof

echo(counter=%counter%

:: build new file
set "file=%~f0"
set "tempFile=%file%.tmp"
set "line="
set /a "n=0"

>"%tempFile%" (
	for /f "tokens=* delims=" %%a in ('findstr /N "^" "%~f0"') do (
		set /a "n+=1"
		set "line=%%~a"
		setlocal enableDelayedExpansion
		if !n! equ 4 (
			set /a "counter+=1"
			echo(set "counter=!counter!"
		) else (
			echo(!line:*:=!
		)
		endlocal
	)
)

:: replace actual batch
(
	endlocal
	>nul copy "%tempFile%" "%file%"
	>nul del "%tempFile%"
	goto :mainEntryPoint
)

penpen

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Self Updating Continuously Running Batch

#4 Post by dbenham » 23 May 2020 05:59

It is hard to imagine a scenario where a self modifying batch file is the best option. It is almost always simpler have static code with various options built in, and use logic to execute the appropriate code.

The only case I can think of where self modifying code might be handy is if the end user dynamically supplies code that cannot be anticipated. Though that could be done simply by letting the user create his/her own batch script and then supply the name of the script to call to your script.

But it is easy enough to write self-modifying code. A better StackOverflow Q&A is Changing a batch file when its running. Within that thread jeb shows a fun, intentionally confusing example.

My answer shows more practical examples of how it could be done.

Rules for a simple implementation:
  • Always modify code that is after the code that creates the change so the running file pointer remains valid.
  • It is simplest if the dynamic code is at the end.
  • Write the new version to a temp file
  • When finished making changes, simply MOVE the temp file to replace the original (the running script)
You can safely prefix each dynamic line with a semicolon prefix (even label lines!). Put all the dynamic code at the end.
When ready to make changes, use FINDSTR /BV ";" "%~F0" >"%~F0.NEW" to copy the original except for dynamic code to a temp file.
Then use as much code as needed to append new dynamic code to the new version.
Finally use MOVE /Y "%~F0.NEW" "%~F0" >NUL to replace your running script with the new version.

Again - although this is easily done, in almost all cases it is better (simpler) to have static code.


Dave Benham

Samir
Posts: 384
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: Self Updating Continuously Running Batch

#5 Post by Samir » 23 May 2020 13:11

Thank you both for your fantastic responses! It is amazing the depth and breath of responses one gets here. 8) Simply fantastic. 8)

You both have made me sit down and think again how I want to approach the task I wish the batch to accomplish. Once I have digested everything, I will post what I come up with and let's see what else can be optimized. :)

pieh-ejdsch
Posts: 240
Joined: 04 Mar 2014 11:14
Location: germany

Re: Self Updating Continuously Running Batch

#6 Post by pieh-ejdsch » 23 May 2020 13:23

This batch does not use a label and can be changed easily, so it is the changeable second part.
Only a copy is made in a subfolder, which then runs and runs ...

Code: Select all

@ rem Don't change this part
@echo off
setlocal
 rem Endless update part. This part controls the copying/updating of the batch.
 rem The batch runs in the subfolder Update.
 rem In the beginning it doesn't matter which batch is started.
for %%a in (Update) do for %%i in ("%~dp0\..\%%a\%~nx0") do if "%%~fi" == "%~f0" (
  >nul 2>nul xcopy /dy "%~dp0..\%~nx0" "%~f0"
 ) else ( >nul 2>nul xcopy /dy "%~f0" "%~f0\..\%%a\"
 "%~f0\..\%%a\%~nx0" %*
)
 rem If the execution is incorrect, the batch is paused so that this error can be eliminated.
 rem This part can therefore also be used for debugging.
if NOT "%~1" == ":notagain" ( for /l %%i in () do ( set /an+=1
  cmd /c "%~f0" :notagain %*
  if errorlevel 1 pause
 )
 exit /b
)
::::::::::::::::::::::::: rem END Endless Part :::::::::::::::::::::::::::::

::::::::::::::::::::::::::::::: Batch ::::::::::::::::::::::::::::::::::::::
 rem This part can be changed as desired, while the batch is being executed,
 rem error messages are also visible and the batch does not abort.
title round %n% %~f0 %*
echo round %n%
echo line 1a

echo line 3a
echo line 4a
echo line 5a
rem ...
Phil

Samir
Posts: 384
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: Self Updating Continuously Running Batch

#7 Post by Samir » 23 May 2020 14:25

Thank you! Another idea to digest. :D It always amazes me how much you guys know about batch--I'm always in awe. 8)

Samir
Posts: 384
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: Self Updating Continuously Running Batch

#8 Post by Samir » 02 Jun 2020 01:32

So I have to admit that my simplistic batch skills made it quite a task just to understand the solutions presented. And even after digesting them, going back to my very simple idea of just copying to a temp and then re-copying and re-executing to make a loop seemed to be the easiest way. Final code (sanitized):

Code: Select all

ECHO OFF

IF /i NOT "%~dp0"=="%temp%" (
 COPY /y "%~dpnx0" "%temp%%~nx0"
 "%temp%%~nx0" %1

)

:MAIN
REM ALL THE MAIN STUFF THAT HAPPENS HERE

REM COPY NEW VERSION TO TEMP AND START AGAIN BUT LOAD THIS COMMAND IN MEMORY FIRST SO IT WILL ALWAYS WORK
(
REM ECHO %0
cmd /c copy /y \\192.168.8.78\BATS\LOCALBAK.BAT %0 & %0
)
Any flaws or potential problems? I've started the production test runs now that the test runs were completed successfully.

Post Reply