switch case with the user given array elements - batch - arrays
I need the solution to the following problem in batch file,
The user gives the input with a space in between every next input element.
The inputs need to be stored in an array as array elements.
The input has to be taken as the case name and the particular case need to be executed.
Hence every case with the name of the array element need to be executed
The array size is not predetermined. It varies as the user may give any number of inputs
The algorithm needs to be like this,
User input numbers are 1 2 4 6 which are stored in the array a[i]
a[i] = {1,2,4,6}
for i = 1 to len(a[i])
CALL :CASE_%a[i]% # jump to :CASE_1, :CASE_2, etc.
:CASE_1
Echo “am in case1”
:: go to the for loop
:CASE_2
Echo “am in case2”
:: go to the for loop
:CASE_3
Echo “am in case3”
:: go to the for loop
:CASE_4
Echo “am in case4”
:: go to the for loop
:CASE_5
Echo “am in case5”
:: go to the for loop
:CASE_6
Echo “am in case6”
:: go to the for loop
:CASE_7
Echo “am in case7”
:: go to the for loop
:CASE_8
Echo “am in case8”
:: go to the for loop
End for
Case_1, Case_2, Case_4, Case_6 only need to be executed as the input is 1 2 4 6.
Is this possible in batch file?
I will split the problem in three parts. Putting the data into the array, getting the data from the array and simulating a case instruction, not present in batch.
#echo off
setlocal enableextensions enabledelayedexpansion
set /p "data=Input data:"
Let's assume the user inputs only numeric values (to avoid all the necessary check and look only to the problem) as indicated, space separated. Put them into a "array". No, arrays are not present in batch scripts, but can be simulated giving to variables the proper names.
set "arrayLength=0"
for %%e in (%data%) do (
set /a "arrayLength+=1"
set "a[!arrayLength!]=%%e"
)
This iterates over the input data, and for each element, a counter is incremented and a variable named a[+counter value+] is created. No, it is not an array, just a variable with a name to allow us simulate the array sintax. As the counter (arrayLength) is beeing changed inside the loop, delayed expansion is needed to read this changed value, and sintax for variable read changes from %var% to !var!
Now, data is in the "array". We are going to iterate over the "array", checking its contents.
for /l %%i in (1 1 %arrayLength%) do (
echo element %%i is : !a[%%i]!
)
The sintax to read the content of each of the elements requires delayed expansion too. In this case we are not changing the value inside the block, but the name of the readed variable is being generated dinamically in each iteration. Remember, no arrays, just variables with an adecuated name. And we generate the name using the for variable.
How to test for the values of the "array"?
echo Test IF
for /l %%i in (1 1 %arrayLength%) do (
if "!a[%%i]!"=="1" (
echo Case 1
) else if "!a[%%i]!"=="2" (
echo Case 2
) else if "!a[%%i]!"=="3" (
echo Case 3
) else if "!a[%%i]!"=="4" (
echo Case 4
) else if "!a[%%i]!"=="5" (
echo Case 5
) else if "!a[%%i]!"=="6" (
echo Case 6
) else (
echo NO CASE
)
)
This iterates over the "array" and uses a cascaded IF sintax to check for the allowed values. It's easy to code, fast but not the most comfortable to maintain if there are frequent changes to the cases.
An alternative to the IF cascade is the usage of subroutines. Depending on the value of the "array" element, call one label or other. Just name the labels adequately.
Then you can test if the label/subroutine exists and then call it.
Or you can call it directly without previous check and test for errors in the call that will indicate the label does not exist.
Or a table of routines can be defined.
For a sample, if the following labels are defined
:case[1]
echo Case 1
goto :eof
:case[2]
echo Case 2
goto :eof
:case[3]
echo Case 3
goto :eof
:case[4]
echo Case 4
goto :eof
:case[5]
echo Case 5
goto :eof
:case[6]
echo Case 6
goto :eof
the code to call this subroutines with a previous check of existence in batch file (%~f0 is the current batch file with full path) could be
rem Use labels in batch with previous test of existence
for /l %%i in (1 1 %arrayLength%) do (
findstr /l /c:":case[!a[%%i]!]" "%~f0" > nul 2>nul
if not errorlevel 1 (
call :case[!a[%%i]!]
) else (
echo NO CASE
)
)
This uses findstr to read the current batch file searching for the :case[n] label. On no error, the label has been found and the call is made. But having to read the batch file to test for the label existence is not the fastest operation.
To not check for label existence and directly do the call, this code can be used
rem Use labels in batch without check
for /l %%i in (1 1 %arrayLength%) do (
ver>nul
call :case[!a[%%i]!] 2>nul
if errorlevel 1 echo NO CASE
)
The 'ver>nul` line symply ensures errorlevel is cleared before calling the subroutine. The call is made and errorlevel is checked. But there is no way of knowing if the errorlevel comes from the call instruction or from the inside of the called subroutine.
Other option is to have a table of rutines to call for each of the posible values of the elements in the array. So if a table for each of the allowed elements is created, pointing the the labels of the subroutines
set "func[1]=:case[1]"
set "func[2]=:case[2]"
set "func[3]=:case[3]"
set "func[4]=:case[4]"
set "func[5]=:case[5]"
set "func[6]=:case[6]"
The following code can call the adecuated subroutine, cheching if the function for the value is defined
for /l %%i in (1 1 %arrayLength%) do (
for %%v in (!a[%%i]!) do if defined func[%%v] (
call !func[%%v]!
) else (
echo NO CASE
)
)
The inner for is needed to get a reference to the value inside the "array" to be used to access the name of the function inside the func "array".
And ..... anything better anyone could imagine.
After all this, Which code should be used? What works for you. It all depends of the real problem to solve
The IF cascade is fast and easy but for a problem with frequent changing cases, is harder to maintain.
The findstr is time consuming.
The call without check can be a real nigntmare.
The function table is in the middle. Is not as fast as having all the code in the block as in the IF solution, but is faster than the findstr while checking for subroutine definition. It is not hard to code, but for small problems is innecesary.
For simple cases, IF constructs are all you need. For complex problems, if the code is long and cases needs to be changed, added, ... the function table makes things easier.
So, it can result in
#echo off
setlocal enableextensions enabledelayedexpansion
set /p "data=Input data:"
set "arrayLength=0"
for %%e in (%data%) do (
set /a "arrayLength+=1"
set "a[!arrayLength!]=%%e"
)
rem func[ allowedValue ] = label to call
set "func[1]=:handleCase_1"
set "func[2]=:handleCase_2"
set "func[3]=:handleCase_3"
set "func[4]=:handleCase_4"
set "func[5]=:handleCase_5"
set "func[6]=:handleCase_6"
for /l %%i in (1 1 %arrayLength%) do (
for %%v in (!a[%%i]!) do if defined func[%%v] (
call !func[%%v]!
) else (
echo NO CASE
)
)
for /l %%i in (1 1 %arrayLength%) do (
if "!a[%%i]!"=="1" (
echo Case 1
rem Or, we can
rem call :handleCase_1
) else if "!a[%%i]!"=="2" (
echo Case 2
) else if "!a[%%i]!"=="3" (
echo Case 3
) else if "!a[%%i]!"=="4" (
echo Case 4
) else if "!a[%%i]!"=="5" (
echo Case 5
) else if "!a[%%i]!"=="6" (
echo Case 6
) else (
echo NO CASE
)
)
endlocal
exit /b
:handleCase_1
echo Case 1
goto :eof
:handleCase_2
echo Case 2
goto :eof
:handleCase_3
echo Case 3
goto :eof
:handleCase_4
echo Case 4
goto :eof
:handleCase_5
echo Case 5
goto :eof
:handleCase_6
echo Case 6
goto :eof
Windows batch does not have true support for arrays, but they can be emulated via clever use of variable names. For example, a[1] and a.len are ordinary variable names, the script does not know of any object named a. I tend to use dot notation instead: a.1, a.2, ... a.len. You are free to develop your own style.
#echo off
setlocal enableDelayedExpansion
set a[1]=1
set a[2]=2
set a[3]=4
set a[4]=6
set a.len=4
:: You can also do multiple numerical assignments on one line using SET /A
:: set /a "a[1]=1, a[2]=2, a[3]=4, a[4]=6, a.len=4"
for /l %%i in (1 1 %a.len%) do (
call :CASE_!a[%%i]!
)
:: You must exit the script so you don't fall into the subroutines after the loop finishes
exit /b
:CASE_1
Echo am in case1
exit /b
:CASE_2
Echo am in case2
exit /b
:CASE_3
Echo am in case3
exit /b
:CASE_4
Echo am in case4
exit /b
:CASE_5
Echo am in case5
exit /b
:CASE_6
Echo am in case6
exit /b
:CASE_7
Echo am in case7
exit /b
:CASE_8
Echo am in case8
exit /b
I reviewed your problem and, in my opinion, it does not require the use of an array. I think you are talking about a list. This way, the stated problem may be solved using a list this way:
#echo off
rem The user gives the input with a space in between every next input element.
set /P input=
rem The input has to be taken as the case name and the particular case need to be executed.
rem Hence every case with the name of the array element need to be executed.
for %%i in (%input%) do call :CASE_%%i
goto :EOF
:CASE_1
Echo am in case1
exit /B
:CASE_2
Echo am in case2
exit /B
:CASE_3
Echo am in case3
exit /B
:CASE_4
Echo am in case4
exit /B
:CASE_5
Echo am in case5
exit /B
:CASE_6
Echo am in case6
exit /B
For example:
C:\> test
1 2 4 6
am in case1
am in case2
am in case4
am in case6
Any solution that is forced to use an unnecessary array would be more complicated...
Related
Sum in batch script
How can I make the sum of the imputed numbers given by the user from the keyboard ? I tried a for loop but is endless. I cannot figure out a break statement. ::#ECHO OFF setlocal EnableDelayedExpansion set /p X= SET /A suma=0 :Loop FOR %%G IN (%X%) DO ( IF %%G GTR 0 ( SET /A suma=%suma%+%%G ) ) SHIFT GOTO Loop :completed echo %suma% What i want to do is to make the program more user friendyl like echo somthing for the user to know it is supposed to write somthing. I know the correct code for this question, but the numbers are given as parameters in the command (syntax: script.bat parameter1 parameter2 parameter3). ::#ECHO OFF SET /A suma=0 :Loop IF "%1"=="" GOTO completed FOR %%F IN (%1) DO ( IF %1 GTR 0 ( SET /A suma=%suma%+%1 ) ) SHIFT GOTO Loop :completed echo %suma% Please give me any idea for the breaking statement in the first example or how can I modify the code to take the numbers from the users imput variable and not as paramaters. Thank you.
SET /A suma=0 set "X=%*" if not defined X set /p "X=No parameters detected " if not defined X ECHO No user-input detected&goto completed FOR %%G IN (%X%) DO ( IF %%G GTR 0 ( SET /A suma=suma+%%G ) ) :completed echo %suma% %* means the command-line tail. If no tail, then ask user for input. If still no data, issue message and show result. shift moves the command line tail one position, so %2 becomes %1, etc. You haven't provided a test to exit the routine - and the command-line tail is presumably empty, so you are shifting it (which does nothing) and looping. The for...%%G.. processes the entire list %X%, so there's no point in the shift/loop - the data has already been processed.
Strange behavior inside IF block in a batch file
I have this batch file here and it doesn't run well. It says "( was unexpected at this time". Do you know why? #ECHO OFF SET A[0]=HOLA SET A[1]=HELLO SET I=0 :LOOP IF DEFINED A[%I%] ( ECHO %I% CALL SET B=%%A[%I%]%% CALL ECHO %%B%% IF %B% == HOLA ( ECHO ES ) ELSE ( ECHO EN ) PAUSE SET /A I+=1 GOTO :LOOP ) My expected output should be: 0 HOLA ES 1 HELLO EN I don't understand why inside IF everything works different. Thanks in advance.
#ECHO OFF SETLOCAL SET "A[0]=HOLA" SET "A[1]=HELLO" SET /a I=0 :LOOP IF DEFINED A[%I%] ( ECHO %I% CALL SET "B=%%A[%I%]%%" CALL ECHO %%B%% FOR /f "delims==" %%b IN ('set B') DO IF /i "%%b"=="B" (IF "%%c"=="HOLA" (SET "Same=Y") ELSE SET "Same=") IF DEFINED Same ( ECHO ES ) ELSE ( ECHO EN ) rem PAUSE SET /A I+=1 GOTO LOOP ) GOTO :EOF Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign a terminal \, Space or " - 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. Your set syntax sets the value of the variable to the rest of the line. Hence, the line including the label loop would be assigned to i. if %B%... substitutes the value of B at the time the block was parsed. AT that time, B was not defined, so nothing is substituted, so the result is if == HOLA (... and cmd does not expect ( at this point and objects. The complex line I've shown performs a set command on all variables that start b and assigns %%b to the variable name, %%c to its current value. There may be many variables that start B, so we need to select exactly B, and if B's value in %%c is HOLA then set Same, otherwise set Same to nothing, which means that Same will either be assigned, or not assigned respectively. if defined operates on the current value of the variable, so same can be used safely to do the if processing. BUT The clean way to do this is by using delayedexpansion. Stephan's DELAYEDEXPANSION link
How do I get user input when starting a batch file and how to separate input into difrent variables
I'm trying to lern how to make batch files, and decided to make a simple calculator, and I want it to take user input when it starts but I don't know how to make it work. What I mean is I write: calc 25 * 78 and it outputs me the result without asking for the arguments again. The way I coded it I need the arguments to be seperated aka: each number and operator have thier own variable and the only way I was able to do that so far is if numbers have set length. Here is my code in case it might help: #echo off set /p Action= podaj dzialanie set number1= %action:~2,1% set number2= %action:~4,1% set operation= %action:~0,1% set /a result= number1 %operation% number2 echo %number% %operation% %number2%=%result%
I'm not sure if I understand how you're intending to use the script, so this is one idea: #Echo Off :PoprosDzialanie For %%G In (Action Integer1 Operator Integer2 Result)Do Set "%%G=" Set /P "Action=podaj dzialanie " If Not Defined Action GoTo PoprosDzialanie Call :AnalizujArgumenty %Action% If ErrorLevel 1 GoTo PoprosDzialanie Set /A result=Integer1 %Operator% Integer2 If Defined Result (Echo %Integer1% %Operator% %Integer2% = %Result% "%__AppDir__%timeout.exe" 3 /NoBreak>NUL) Rem Your script continues between this line and the next none empty line. GoTo :EOF :AnalizujArgumenty If Not "%4"=="" Exit /B 1 If "%3"=="" Exit /B 1 2>NUL Set /A Integer2=%3 If ErrorLevel 1 Exit /B 1 If Not "%2"=="*" If Not "%2"=="/" If Not "%2"=="+" If Not "%2"=="-" Exit /B 1 Set "Operator=%2" 2>NUL Set /A Integer1=%1 If ErrorLevel 1 Exit /B 1 Exit /B The input is sent to :AnalizujArgumenty where each argument is analysed to ensure that only three arguments were passed and that those arguments were valid, i.e integer operator integer, (where operator can be only *, /, +, or -). If those pass analysis the variables are defined, and your calculation is performed, otherwise they're undefined and the action prompt is repeated. If you have other actions to perform in your script, those can be added where Remarked, (you may optionally delete the Remark).
It's easy when you rely on correct parameters: #echo off set /a "result=%*" echo Result is %result% Works with or without spaces: test.bat 5 + 3 test.bat 3*4 A bit more code, if you want to ask the user when there are no parameters: #echo off if "%*"=="" goto :AskUser set /a "result=%*" || goto :AskUser echo Result is %result% goto :eof :AskUser REM no or invalid parameter(s) echo some explanation of what input is expected. set /p "Action= podaj dzialanie : " set /a "result=%action%" || goto :AskUser echo Result is %result% %* is "all parameters". (%1 is the first parameter, %2 the second, etc. until %9, if you want to check each parameter, but then you lose the advantage to omit the spaces)
Batch file doesn't work, how can I to fix it?
I want to write a game using a batch script, but there is an error and I don't know what to do. #echo on goto log :inicio set "esquerda=caverna" set "esquerda2=6" set /p "run=Digite a acao: " if %run%==help ( goto help) else ( goto comands) :carvena echo oi>"%userprofile%\desktop\oi.txt" pause>nul :comands echo %run% >"%tmp%\reino_de_merlock\personagem\comands.txt" cd "%tmp%\reino_de_merlock\personagem" type comands.txt | find /i "andar_esquerda" && echo andar>andar_esquerda.txt if exist andar_esquerda.txt ( set "andar=esquerda1" del /q andar_esquerda.txt goto andar1) :log for /f %%a in ('type "%tmp%\reino_de_merlock\personagem\agilidade.txt"') do ( set "agilidade=%%a" & goto inicio) :andar1 if "%andar%" == "esquerda1" ( set /a andar = agilidade - esquerda2 if %andar% LEQ 0 ( goto %esquerda%)) 1>nul 2>nul pause>nul The error is in set /a andar = agilidade - esquerda2, the variable becomes esquerda1 and the right it's -2, what is the error?
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed. Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered. Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values. In your case, if %andar% LEQ 0 ( goto %esquerda%) is contained within the block that starts if "%andar%" == "esquerda1" ( and consequently uses the values of andar and esquerda1 as they were when the if "%andar%" == "esquerda1" was reached, not on the new value of andar calculated within the loop. Look for many SO entries on 'delayed expansion'
.bat script, 4 lists as data, input is an integer i, output is the rank of the list containing i
I need to write a script, in.bat, where the user inputs a 3 digits number (as a string) i. the script has 4 predefined groups of numbers, number from 1 to 4 the script tests membership for i in the groups, and return the index of the group containing i. I'm not familiar with declaring and initializing any kinds of data structure (e.g. list, arrays and the like) for batch files, so can someone help me on this? Pseudo code: ::Returns 1,2,3,4,5 Depending on testNum passed group1= <822-824,829,845,851,859,864,867> group2= <826-828,830-839,843-844,847-850,852-854,860-862,883> group3= <855-858,861,863,865> group4= <877-882,884> if %1 is member of group1 return 1 if %1 is member of group2 return 2 if %1 is member of group3 return 3 if %1 is member of group4 return 4 Thank you!
Batch does not have any formal complex data structures like arrays, lists, or objects. But you can emulate them. Here is an efficient solution that defines the groups with nearly the format as in your question. #echo off setlocal enableDelayedExpansion ::Here is a small loop to test the routine for %%N in (822,823,883,835,856,863,880,884) do ( call :assignGroup %%N echo %%N is in group !group! ) exit /b :assignGroup CaseNumber :: The returning value is contained in variable GROUP set group=0 for %%A in ( "822-824,829,845,851,859,864,867" "826-828,830-839,843-844,847-850,852-854,860-862,883" "855-858,861,863,865" "877-882,884" ) do ( set /a group+=1 for %%B in (%%~A) do ( for /f "tokens=1,2 delims=-" %%C in ("%%B") do ( if "%%C"=="%~1" exit /b if "%~1" gtr "%%C" if "%~1" leq "%%D" exit /b ) ) ) ::no group found so undefine the var set "group=" exit /b The above solution is fine for occasional calls. But if you were going to call the routine many thousands of times, then it would be better to initialize an array of valid values with assigned group numbers. Then each test becomes a direct read of the value, instead of having to call a routine. However, it is possible to abuse this technique. Assign enough values and each variable assignment gets slower and slower. You might also spend more time setting up the array than actually testing values. Note there is no significance to the characters []. in the variable names. They could be stripped out of the variable names and the code would function the same. They are there only to aid in the understanding the intent of the variables. #echo off setlocal enableDelayedExpansion ::initialize a sparse "array" that assigns a group to each valid case # set group=0 for %%A in ( "822-824,829,845,851,859,864,867" "826-828,830-839,843-844,847-850,852-854,860-862,883" "855-858,861,863,865" "877-882,884" ) do ( set /a group+=1 for %%B in (%%~A) do ( for /f "tokens=1,2 delims=-" %%C in ("%%B") do ( if "%%D"=="" ( set case[%%C].group=!group! ) else for /l %%N in (%%C 1 %%D) do ( set case[%%N].group=!group! ) ) ) ) ::Now test some values for %%N in (822,823,883,835,856,863,880,884,900) do ( if defined case[%%N].group ( echo %%N is in !case[%%N].group! ) else ( echo %%N is not in a group ) ) exit /b
This will set GROUP to whatever group it finds the code in set test=822,823,824,829,845,851,859,864,867 echo %test% | findstr %1>nul&&set group=1 set test=826,827,828,830,831,832,833,834,835,836,837,838,839,843,844,847,848,849,850,852,853,854,860,861,862,883 echo %test% | findstr %1>nul&&set group=2 set test=855,856,857,858,861,863,865 echo %test% | findstr %1>nul&&set group=3 set test=877,878,879,880,881,882,884 echo %test% | findstr %1>nul&&set group=4 if you want to use ERRORLEVEL to test the return value, then change the SET GROUP= to EXIT /B
By no means perfect, but a working starting point. Save the following script as group.bat and call it with group 878 to find out to which group 878 belongs to. #echo off SET group1=822-824,829,845,851,859,864,867 SET group2=826-828,830-839,843-844,847-850,852-854,860-862,883 SET group3=855-858,861,863,865 SET group4=877-882,884 CALL :IsInGroup %1 "%group1%" IF Errorlevel 1 echo Group 1 & GOTO :EOF CALL :IsInGroup %1 "%group2%" IF Errorlevel 1 echo Group 2 & GOTO :EOF CALL :IsInGroup %1 "%group3%" IF Errorlevel 1 echo Group 3 & GOTO :EOF CALL :IsInGroup %1 "%group4%" IF Errorlevel 1 echo Group 4 & GOTO :EOF echo Group not found GOTO :EOF :IsInGroup SETLOCAL ENABLEDELAYEDEXPANSION FOR %%i IN (%~2) DO ( SET h=%%i SET g=!h:~3,1! SET /a lo=!h:~0,3! IF !g!. == -. ( SET /a hi=!h:~4,3! IF %1 GEQ !lo! ( IF %1 LEQ !hi! exit /B 1 ) ) ELSE ( IF %1 EQU !lo! exit /B 1 ) ) ENDLOCAL EXIT /B 0 The function :IsInGroup checks whether the first argument is contained in the list passed as the second argument.
If the number of values to check for in each group is small, dbenhams second method (direct read of each array value) is the fastest. Any other method that process the values of each group in a FOR loop to do individual or range comparisons is slower. However, as the number of individual elements grows (counting each element included between a range) array value method get slower, as dbenhams indicated. There is another approach to solve this problem using an aritmethic expression. For example, you may check if a variable is 829 or 845 with this command: set /A result=(829-variable)*(845-variable) If the variable have anyone of these two values the result is zero. To check if the variable is into a range, the expression is this: set /A aux=(lowerLimit-variable)*(variable-upperLimit), result=(aux-1)/aux Previous expression requires a small provision in case the variable is anyone of the limits (to manage the division by zero). The program below assemble the appropiate aritmethic expression for each of the groups; after that, checking each value is achieved with a maximum of 4 SET /A commands (one per group). This method is faster than individual testing of each value in a FOR loop and use just one variable per group, not per individual element. #echo off setlocal EnableDelayedExpansion rem Assemble testing expression for each group set numGroup=0 for %%a in ( "822-824,829,845,851,859,864,867" "826-828,830-839,843-844,847-850,852-854,860-862,883" "855-858,861,863,865" "877-882,884" ) do ( set expr=1 for %%b in (%%~a) do ( for /F "tokens=1,2 delims=-" %%c in ("%%b") do ( if "%%d" equ "" ( rem Individual value: multiply previous expr by direct subtract set "expr=!expr!*(%%c-n^)" ) else ( rem Range value pair: use range expression at this point, then continue set "expr=!expr!,a=r,r=0,b=(%%c-n^)*(n-%%d),r=(b-1)/b*a" ) ) ) set /A numGroup+=1 set expr[!numGroup!]=!expr! ) rem Now test some values for %%n in (822,823,883,835,855,856,858,863,880,884,900) do ( call :assignGroup %%n echo %%n is in group !group! ) goto :EOF :assignGroup number set /A n=%1, group=0 for /L %%i in (1,1,%numGroup%) do ( set /A r=!expr[%%i]! 2> NUL if !r! equ 0 set group=%%i & exit /B 0 ) exit /B 1