Home > Mobile >  Display Timer while a command is being executed in a batch file
Display Timer while a command is being executed in a batch file

Time:11-26

Edit: I shall thank Magoo for the detailed answer. I edited my batch file according to Magoo's answer. Here is the new code:

@echo off
mode 62,22
:Begin
choice /c 12345 /M "Insert a number (min. 1 - max. 5): "
set "CommandVar0=%errorlevel%"
choice /c 12345 /M "Please confirm the number you entered: "
set "CommandVarC=%errorlevel%"

if %CommandVarC% NEQ %CommandVar0% (
 echo Insert a matching number between 1~5 for confirmation
 goto Begin
)

if %CommandVar0% == 1 set /P CommandVar1=Insert ID: 
if %CommandVar0% == 2 set /P CommandVar1=Insert ID: & set /P CommandVar2=Insert ID: 
if %CommandVar0% == 3 set /P CommandVar1=Insert ID: & set /P CommandVar2=Insert ID: & set /P CommandVar3=Insert ID: 
if %CommandVar0% == 4 set /P CommandVar1=Insert ID: & set /P CommandVar2=Insert ID: & set /P CommandVar3=Insert ID: & set /P CommandVar4=Insert ID: 
if %CommandVar0% == 5 set /P CommandVar1=Insert ID: & set /P CommandVar2=Insert ID: & set /P CommandVar3=Insert ID: & set /P CommandVar4=Insert ID: & set /P CommandVar5=Insert ID: 

:loop
start EXAMPLE.exe %CommandVar1%
if defined commandvar2 start EXAMPLE.exe %CommandVar2%
if defined commandvar3 start EXAMPLE.exe %CommandVar3%
if defined commandvar4 start EXAMPLE.exe %CommandVar4%
if defined commandvar5 start EXAMPLE.exe %CommandVar5%
rem wait 10 seconds
for /L %%y in (1,1,10) do (
 timeout /t 1 > nul
 tasklist /fi "imagename eq EXAMPLE.exe" |find ":" > nul
 if NOT errorlevel 1 goto begin
)
taskkill /f /im EXAMPLE.exe
timeout /t 5 
goto loop

The issue I'm having right now is that;

  1. Due to my lack of knowledge, I don't know how to expand this command:
set "commandvar1="
set "commandvar2="
set /P CommandVar1=Insert ID: 
if not defined commandvar1 goto begin
if "%CommandVar0%"=="2" (
 set /P CommandVar2=Insert ID: 
 if not defined commandvar2 goto begin
)

e.g. to set "commandvar5=" etc. So instead I'm still using my complicated command which does the job for now.

  1. How can I add the normal timer to this command?
for /L %%y in (1,1,10) do (
 timeout /t 1 > nul
 tasklist /fi "imagename eq EXAMPLE.exe" |find ":" > nul
 if NOT errorlevel 1 goto begin
)

I want a timer to actually display the countdown of the command being executed like the usual timeout /t command if possible.

CodePudding user response:

Addressing the core of the problem:

start EXAMPLE.exe %CommandVar1% & start EXAMPLE.exe %CommandVar2%

Will start two instances of example.exe passing the contents of commandvar? which may be response to "Insert ID:" or (rarely) nothing

Immediately thereafter, you are executing tasklist and looking for :.

If either the tasks have actually been established and is running, the tasklist output will NOT contain : so find will NOT find : and hence set errorlevel to 1

If the tasks have not been started or have both terminated, then the output of tasklist would be INFO: No tasks are running which match the specified criteria. which contains : and hence errorlevel will be set to 0.

Your next line says if **either** task is running (errorlevel 1), say "not found" and go to Begin otherwise (ie. neither task is running) then delay, taskkill the non-existent tasks, delay again and go back to Begin.

Another hidden problem is that when the routine returns to begin, if CommandVar2 has been set, then it will not be cleared, so it will remain set for the next input-cycle, regardless of the data input.

So we need to tackle the logic problems as well as the batch-syntax-specific problems.

Tip: Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign " or a terminal backslash or Space. Build pathnames from the elements - counterintuitively, it is likely to make the process easier. If the syntax set var="value" is used, then the quotes become part of the value assigned.

First thing to tackle is the choose-and-check part. The value assigned to a variable by a set /p can be any string. That string may be the expected string or an unexpected string (obviously). An unexpected string may take many forms - it might contain spaces for instance, or unbalanced quotes, or % or parentheses or other strings or characters that have significance in the batch language. Also, responding with Enter to a set /p will leave the variable unchanged, not set it to nothing.

When the obvious parameter-check is executed via if %var1% == %var2% ..., then the values of the variables are substituted, and the comparison executed, so had the user input break me for instance, then batch would attempt to execute if break me == 2 ... and batch would see me where it expects to see a comparison-operator like ==.

The usual way to by-pass this problem is by "quoting both sides", ie. if "%var1%" == "%var2%" ... This is useful in the case that you may be processing some string containing spaces that is being returned from a command, but what happens if the user enters break " me ?

Consequently, the recommendation is to use the choice command to make 1-character choices (see choice /? from the prompt for documentation, or thousands of items on SO for examples)

Hence, your code should be

choice /c 12 /M "Insert a number (min. 1 - max. 2): "
set "CommandVar0=%errorlevel%"
choice /c 12 /M "Please confirm the number you entered: "
set "CommandVarC=%errorlevel%"

At this point, we are sure that commandvar? contains 1 or 2, so we can indeed use

if %CommandVarC% NEQ %CommandVar0% (
 echo Insert a matching number between 1~2 for confirmation
 goto Begin
) 

Note: I've used the string-assignment syntax, even though the value assigned from %errorlevel% must be a pure-numeric string. It's also possible to use set /a var=%errorlevel% here. set /a assigns a value that we know is numeric (and can also do calculations) and needs no quotes.

There's no point in else... here -it serves to complicate matters. The code will simply continue to the next line if the goto is not executed.

 if %CommandVarC% GTR 2 (echo Maximum number is 2.
    goto Begin
    ) else (

is not required. We know that CommandVarC can only be 1 or 2.

if %CommandVar0% == 1 set /P CommandVar1=Insert ID: 
if %CommandVar0% == 2 set /P CommandVar1=Insert ID: & set /P CommandVar2=Insert ID: 

Well, this is overcomplicated, and doesn't quite do what is required. CommandVar1 is always required, and CommandVar2 will remain set if it has been set in the past.

Try:

set "commandvar1="
set "commandvar2="
set /P CommandVar1=Insert ID: 
if not defined commandvar1 goto begin
if %CommandVar0% == 2 set /P CommandVar2=Insert ID: 

Well, primitively. We know commandvar0 is a single digit, so we can use a simple ==. We also may or may not have received a response for commandvar2.

So

if "%CommandVar0%"=="2" (
 set /P CommandVar2=Insert ID: 
 if not defined commandvar2 goto begin
)

may be more "according to Hoyle"

Summing up (before we tackle the next part), try using

choice /c 12 /M "Insert a number (min. 1 - max. 2): "
set "CommandVar0=%errorlevel%"
choice /c 12 /M "Please confirm the number you entered: "
set "CommandVarC=%errorlevel%"

if %CommandVarC% NEQ %CommandVar0% (
 echo Insert a matching number between 1~2 for confirmation
 goto Begin
) 

set "commandvar1="
set "commandvar2="
set /P CommandVar1=Insert ID: 
if not defined commandvar1 goto begin
if "%CommandVar0%"=="2" (
 set /P CommandVar2=Insert ID: 
 if not defined commandvar2 goto begin
)

If we get past this point, I gather we should launch the executable, possibly twice, then wait for it to run, with a run-time limit of 10 seconds.

So,

start EXAMPLE.exe %CommandVar1%
rem only start a second instance if commandvar2 has been specified
if defined commandvar2 start EXAMPLE.exe %CommandVar2%
rem wait a sec...or 10
for /L %%y in (1,1,10) do (
 timeout /t 1 >nul
 tasklist /fi "imagename eq EXAMPLE.exe" |find ":" > nul
 if NOT errorlevel 1 goto begin
)
rem kill tasks still running
taskkill /f /im EXAMPLE.exe
timeout /t 5 
goto begin

for /L is explained at for /? from the prompt. Here, it counts %%y from 1 to 10 in steps of 1.

Each step delays 1 second (the >nul suppresses the countdown) then tests whether an executable is running. If NONE is running, then the tasklist will report a line containing : and errorlevel will be set to 0.

IF ERRORLEVEL n is TRUE if the runtime (ie. current) errorlevel is n or greater than n. IF ERRORLEVEL 0 is therefore always true. IF NOT ERRORLEVEL 1 is a test for errorlevel=0.

So, if there is no executable running, goto begin.

Once this test has been done 10 times, if an executable is running, then we exit the for /L loop and taskkill the remaining task(s) and back to the future...

CodePudding user response:

Parham.8, the error level is set after each command has been executed, if the next command succeeds, the error level will take 0 independent of the previous one. Use && to execute a command only if the previous command's error level is 0. Ex.

start EXAMPLE.exe %CommandVar1% && start EXAMPLE.exe %CommandVar2% && tasklist /fi "imagename eq EXAMPLE.exe" |find ":" > nul 
  • Related