2

I have the following batch script (slightly simplified) to run a series of exe files in parallel.

SETLOCAL ENABLEDELAYEDEXPANSION

for %%a in (1 2 4 8) do ( 
  set i=%%a
  set script=calculate_V!i!.exe
  start echo started V!i! at !time:~0,5! ^>^> log.txt ^2^>^&^1 
 ^& !script! ^& echo ended V!i! at !time:~0,5! ^>^> log.txt ^2^>^&^1 ^& exit
)

I want to get the start and end time of the script's run, but the problem is that the delayed expansion of the second time (echo ended V!i! at !time:~0,5!) is made simultaneously with the first, so the output is (for example)

started V1 at 15:50
started V2 at 15:50
...
ended V1 at 15:50
ended V2 at 15:50
...

even though the script took 10 minutes to run.

How can I evaluate !time:~0,5! only after script runs?

Thanks

8
  • Are the EXE files command-line utilities, or GUI applications?
    – AFH
    Commented Jun 17, 2019 at 15:21
  • exe files are compiled from matlab and i have no access to the source code
    – fdiogo
    Commented Jun 17, 2019 at 15:24
  • Do the completion messages come out after the scripts have finished, but with the wrong time?
    – AFH
    Commented Jun 17, 2019 at 15:39
  • Nothing comes out of the script, it just creates a file. I want the execution time to come from echo ended at !time:~0,5!
    – fdiogo
    Commented Jun 17, 2019 at 15:59
  • You say the scripts run for ten minutes, so do the end messages come out immediately or ten minutes later?
    – AFH
    Commented Jun 17, 2019 at 16:05

2 Answers 2

2

I have looked at this and the only way I can get it to work is to make sure that the time look-ups are on separate lines, and I have not managed to do this without using two batch files.

I have used timeout /t as a substitute for running a task which takes a specific time.

launcher.cmd:-

@echo off
echo.
echo %time% start %1 >>logfile.txt
timeout /t %1 2>&1 1>nul:
echo %time% end %1 >>logfile.txt
exit

scheduler.cmd:-

@echo off
start /b launcher 5
start /b launcher 10

logfile.txt:-

20:24:01.15 start 5
20:24:01.22 start 10
20:24:06.20 end 5
20:24:11.19 end 10

It should be straightforward to adapt these files for your purposes.

Notes:-

  • start /b stops multiple cmd windows from opening; alternatively, start /min will use separate windows, but without too much visual intrusion.
  • Because time is a volatile variable, it does not need to use delayed expansion.
  • If the scheduled task is a Windows (not a command-line) program, launcher will need to use start /wait to run it.
  • The exit makes sure that the launcher threads terminate.
3
  • Thanks, that does work! It is still I bit more clumbersome than I would have liked, I was hoping there would be a one-liner, but I'll take it :)
    – fdiogo
    Commented Jun 18, 2019 at 13:55
  • I had hoped that launcher.cmd could be incorporated as a subroutine within scheduler.cmd, but sadly you can't use start /b :launcher ..., so I was left with my inelegant solution (very frustrating to someone used to bash).
    – AFH
    Commented Jun 18, 2019 at 15:53
  • @AFH It's possible to call an incorporated subroutine, see my answer
    – jeb
    Commented Aug 25, 2021 at 6:26
0

This script is equivalent to the solution of @AFH, but uses the trampoline technique.
This enables the possibility to start a subprocess at a label in the same batch file.

Additionally it waits for the end of both tasks.
I borrowed the waiting technique from dbenham's post Waiting for parallel batch scripts

@echo off
REM *** This is a trampoline to jump to a function when a child process shall be invoked
for /F "tokens=3 delims=:" %%L in ("%~0") do goto %%L

:scheduler
set "lock=%temp%\wait%random%.lock"

:: Launch one and two asynchronously, with stream 9 redirected to a lock file.
:: The lock file will remain locked until the script ends.
:: The batch file calls itself by using %~dpnx0, but hides the label name into the full path
start "title" /b call "%~d0\:launcher:\..%~pnx0" "timeout /t 5" 9>"%lock%1" 
start "title" /b call "%~d0\:launcher:\..%~pnx0" "timeout /t 10" 9>"%lock%2" 

:Wait for both scripts to finish (wait until lock files are no longer locked)
1>nul 2>nul ping /n 2 ::1
for %%N in (1 2) do (
  ( rem
  ) 9>"%lock%%%N" || goto :Wait
) 2>nul

::delete the lock files
del "%lock%*"

exit /b 

:launcher
echo Launched "%~1"
echo %time% start "%~1" >>logfile.txt
REM *** Execute the command, it's in the first argument
%~1
echo %time% end "%~1" >>logfile.txt
echo End of "%~1"
exit

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .