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;
- 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.
- 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