Comparing two strings in batch - batch-file

Currently I am writing a batch file to accept a parameter and jump to a specific part of the file based on the parameter value. The code I have is as follows:
SET param = %~n1
IF "%param%"=="q" GOTO :QUICK
IF "%param%"=="t" GOTO :THOROUGH
IF "%param%"=="b" GOTO :BOOT
IF "%param%"=="f" GOTO :FIX
IF "%param%"=="" GOTO :INVALID
:QUICK
echo "Quick"
pause
exit
:INVALID
echo "Invalid"
pause
exit
:BOOT
echo "Boot"
pause
exit
:FIX
echo "Fix"
pause
exit
:THOROUGH
echo "Thorough"
pause
exit
The only parameters the script should accept are /q, /t, /b or /f (or without /), and when an incorrect parameter is supplied, it should jump to INVALID. When I run it with an invalid parameter, it works, however, if I supply a parameter that is correct (for example, file.bat t) the result fails to work as I hope, and ends up going directly to INVALID. I have tried using "%param%" EQ "q", and setting q to a variable before doing the comparison, but I have had no luck coming up with a result that works.

you don't have a parameter %param%. But you have a parameter named %param<space>% And it's value isn't q, but <space>q
Write your setcommand without spaces:
set param=%~n1
or even better (to avoid unintended spaces at the end):
set "param=%~n1"
Note: you can make your parameters case independent with if /i "%param%"=="q"

Related

Batch "if" statement not working

I seem to have a problem with my "if" statements. Currently after the pause in "start" the file just closes and nothing else happens. Chances are, I have no idea what I'm doing.
#echo off
set startnum=0
goto start
:start
pause
set startnum="!startnum!"+1
if "%startnum%"="%0%" goto fail
if "%startnum%"="%1%" goto success
goto start
:success
cls
echo It worked!
echo "%startnum%"
pause.
exit
:fail
cls
echo Failure
pause.
exit
First problem:
set startnum="!startnum!"+1
Evidently, you wish to add 1 to startnum.
Your set command would set startnum to "!startnum!"+1. Literally. To perform arithmetic, you need set /a.
set /A startnum="!startnum!"+1
well, this won't work as "!startnum! isn't numeric. Had you invoked delayedexpansion beforehand, then the value of startnum would have been substituted for !startnum! yielding set /A startnum="0"+1 which makes more, but still not much sense.
set /A startnum=startnum+1
adds 1 to startnum - see set /? from the prompt for documentation.
set /A startnum+=1
would also add 1 to startnum.
Next problem.
if "%startnum%"="%0%" goto fail
Well, you appear to have found lss and all that gang. Problem is that the simple comparison operator is ==, not =.
if "%startnum%"=="%0%" goto fail
Now - what will that do? It will compare "thecontentsofstartnum" to "thecontentsof0". Since both of these arguments are quoted, batch will perform a string comparison. With a string comparison, 123 is less than 89 because 1 is less than 8.
But - you are attempting an equivalence comparison (equ as the operator may be used instead of ==) so the preceding point is simply AAMOI.
The difficulty is %0% which you may believe attempts to extract the value of the variable 0 but actually it replaces %0 with the value of the 0th parameter to the batchfile, which is the batchfile name itself, so you get "batchfilename%" - probably not what you actually wanted.
if "%startnum%"=="0" goto fail
is the way to implement that test.
The first IF statement is preprocessed by cmd.exe to
if ""!startnum!"+1"="test.bat" goto fail
which is a completely invalid IF condition.
cmd.exe outputs a syntax error message because of "="test.bat"" and exits batch file processing. This can be seen by debugging the batch file.
The solution is using right syntax for
assigning a value to an environment variable,
an arithmetic expression,
and last but not least the IF condition itself.
The batch file code fixed:
#echo off
set "startnum=0"
goto Begin
:Begin
set /A startnum+=1
if "%startnum%" == "0" goto Fail
if "%startnum%" == "1" goto Success
goto Begin
:Success
cls
echo It worked!
echo "%startnum%"
pause
exit /B
:Fail
cls
echo Failure
pause
exit /B
It would be safe here to remove all double quotes on both IF conditions.
One more hint: Don't use the name of a command like START as label. It works, but it should be avoided in case of ever adding to batch file the command START and searching for either command or label.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains how to reference batch file arguments.
cls /?
echo /?
exit /?
goto /?
if /?
pause /?
set /?
Further read the answers on following questions:
Batch file comparison of variable with constant fails
Why is no string output with 'echo %var%' after using 'set var = text' on command line?
Where does GOTO :EOF return to?
Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files

Difficulty using set/endlocal in Batch across files

I'm trying to call one bat file from another, while keeping the target variables local to itself(mostly). The code below is my failed attempt, the var i want is missing, but the local is still around.
I've found some info on using setlocal here, which is how I think I have it. Also the info I'm using to push a var past setlocal is here. It's very possible I'm missing something from these. Any help is appreciated!
The calling bat:
#SET errmsg=Old Message
#CALL Target.bat TEST_JOB errmsg
#ECHO.jobname = %jobname%, but should be undefined
#IF DEFINED errmsg ECHO.Error occurred: %ERRORLEVEL% %errmsg%
The target bat:
#SETLOCAL
#ECHO OFF
:START
SET jobname=%~1
SET errmsgvar=%~2
:MAIN
CALL:ERROR "New Error Message"
ECHO.Should have never returned here
ENDLOCAL
:EXIT
#ECHO ON
#EXIT /b %ERRORLEVEL%
:ERROR "errorMesage"
ENDLOCAL & SET "%errmsgvar%=%~1"
ECHO.%errmsg% ^<-- Testing only, we don't know what the actual var will be
(GOTO) 2>NUL & GOTO:EXIT
The result:
C:\Projects\Batch>Caller.bat
New Error Message <-- Testing only, we don't know what the actual var will be
jobname = TEST_JOB, but should be undefined
Error occurred: 0 Old Message
Edit for clarity:
I'm trying to accomplish several things here...
Allow the caller to specify what var the error message should be stored in | 2nd param in call
On an error exit immediately, saving the error message to the provided var | :ERROR block
Keep all vars in target local, push error message through by setting it on the endlocal line
It seems like my endlocal is being ignored, and its just doing endlocal at the end of the file, which breaks things
As Magoo said, your TEST_JOB value is cleared properly. Your test must have been looking at a holdover result from a prior run. Best to explicitly clear the value in your calling bat, prior to the CALL, so you can never get a false result..
Your errmsg is not being set because of a flaw in your logic. More on that after I provide a little introduction to (goto) 2>nul.
You are attempting to use a relatively new (goto) 2>nul technique that is not widely known. It is effectively an exit /b except additional concatenated commands still execute, but in the context of the caller. I believe the first discovery was published at http://forum.script-coding.com/viewtopic.php?id=9050 (which I cannot read), and the first known English posting is at http://www.dostips.com/forum/viewtopic.php?f=3&t=6491.
Since that DosTips post, many useful tools have resulted:
RETURN.BAT - a function to safely return any value across the ENDLOCAL barrier. This function is a derivative of jeb's original idea
PrintHere.bat - a partial emulation of the unix here doc functionality
EXCEPTION.BAT - Effective exception handling within batch scripts
Within your code, you try to ENDLOCAL in your error routine, but that only affects SETLOCAL that were issued while in your routine. You need to use the (goto) 2>nul trick prior to issuing the ENDLOCAL so that ENDLOCAL works properly on the parent context.
:error "errormesage"
(
(goto) 2>nul
endlocal
set "%errmsgvar%=%~1"
goto :exit
)
I'm worried about your returned ERRORLEVEL. I don't think it is returning the value you want when there is an error.
You must remember that all external commands always set the ERRORLEVEL whether there was an error or not. Almost all internal commands set the ERRORLEVEL to non-zero upon error, and some internal commands set the ERRORLEVEL to 0 upon success (but some preserve the existing ERRORLEVEL if there was no error).
It is safest to explicitly pass your desired error number into your :error routine, and then explicitly set the value upon exit. Here is one way to do it:
:error "errMsg" errNum
(
(goto) 2>nul
endlocal
set "%errmsgvar%=%~1"
cmd /c exit %2
goto :exit
)
But I would modify things so that you always exit the same way regardless whether there was an error or not. The :exit routine below is called with the error message and error number if there was an error, and the values are set appropriately. Upon normal exit, neither value is passed in, so the errmsg variable gets cleared, and the routine returns with the current ERRORLEVEL (presumably 0).
Calling script
#setlocal
#set errmsg=Old Message
#set "jobname="
#call target.bat TEST_JOB errmsg
#if defined jobname (
echo ERROR - jobname = %jobname%
) else (
echo SUCCESS - jobname is undefined
)
#if defined errmsg (
echo.Error occurred: %errorlevel% %errmsg%
) else (
echo No error occurred
)
Target.bat
#echo off
setlocal enableDelayedExpansion
:start
set jobname=%~1
set errmsgvar=%~2
:main
set /a "1/(%random% %% 3)" || call :exit !errorlevel! "Random error"
echo Success
call :exit
:exit [errNum] ["errMsg"]
(
(goto) 2>nul
endlocal
set "%errmsgvar%=%~2"
echo on
exit /b %1
)
The :main code randomly raises an error 33% of the time when it attempts to divide by zero.
Here is some sample output, showing both possible outcomes:
C:\test>test
Success
SUCCESS - jobname is undefined
No error occurred
C:\test>test
Divide by zero error.
SUCCESS - jobname is undefined
Error occurred: 1073750993 Random error
Worked perfectly for me.
I believe your test set jobname at some stage and hence your setlocal/endlocal frames simply restore the original environment.
I'd suggest you execute
set "jobname="
as the first line of your calling bat to force jobname to be clear before the action starts.
Change your second script to the following. If accounts for the ENDLOCAL at the end of the script. I believe the ENDLOCAL in the :ERROR block is for that block only and not the entire file.
#SETLOCAL
#ECHO OFF
:START
SET jobname=%~1
SET errmsgvar=%~2
:MAIN
CALL:ERROR "New Error Message"
ECHO.Should have never returned here
ENDLOCAL
:EXIT
REM case insensitive test for errmsgvar.
IF DEFINED errmsgvar (
IF /I NOT "%errmsgvar%" == "" (
ENDLOCAL & SET "errmsg=%errmsg%"
)
)
#ECHO ON
#EXIT /b %ERRORLEVEL%
:ERROR "errorMesage"
ENDLOCAL & SET "errmsgvar=%~1"
SET "errmsg=%errmsgvar%"
ECHO.%errmsg% ^<-- Testing only, we don't know what the actual var will be
(GOTO) 2>NUL & GOTO:EXIT
Output becomes (extra line breaks for clarity):
Caller.bat
New Error Message <-- Testing only, we don't know what the actual var will be
jobname = TEST_JOB
Error occurred: 0 New Error Message
Change 2nd last line to
ECHO.%errmsgvar%.....
to match the 3rd to last line
By way of explanation...
ENDLOCAL & SET "errmsgvar=%~1"
1. The entire line loaded and %~1 is expanded.
2. ENDLOCAL is executed and ends localization.
3. SET "errmsgvar=%~1" is executed as...
SET "errmsgvar=WhateverWasIn%~1"
This technique is tunneling and is a way to pass variables across locales.

Troubles with goto(cmd)

#echo off
:WriteAgain
set x=
set /p Variables=Write your expression
set /a x=%Variables%
if %errorlevel% neq 0 goto ErrorOccured
echo %x%
goto :eof
:ErrorOccured
echo.Your expression is not valid
goto WriteAgain
:eof
Greeting, It is supposed to be a simple calc, but for some reasons, when "if" works(for 1/0) it looks like "goto" doesnt(I may be mistaken here). Could you help me to solve this problem? Also I am thinking about typing error in any txt: should I use 2>txt_name.txt after neq 0 or what?
goto :eof is a built-in construction to return from a subroutine (call :subroutine). It exits current batch file when used not in a subroutine.
Rename the label to end, for example.
Or use exit instead of goto to the end of batch file.
For output redirection examples and syntax see http://ss64.com/nt/syntax-redirection.html so in your case echo prints to standard output thus > must be used:
echo Your expression is not valid >errlog.txt
Some utilities indeed print the errors to STDERR and the standard > won't catch the messages, so command 2>errlog.txt should be used.
You don't put
goto :eof
Try using
goto eof
And also I am not sure but maybe the name eof is no good (Is used by CMD itself) so keep things simple and use any other name like "exit, problem, fail, etc..."

Batch command line argument matching

I really can't understand why this refuses to work.
#ECHO OFF
SET CURRDIR=%CD%
if [%1%]==[1] GOTO ONE
if [%1%]==[2] GOTO TWO
if [%1%]==[3] GOTO THREE
:ONE
call "%CURRDIR%\PlanningProduct.bat"
:TWO
call "%CURRDIR%\Organization.bat"
:THREE
call "%CURRDIR%\Measure.bat"
pause
I did the following in the command line
I:\BatchMania>I:\BatchMania\Home.bat 1
and the output I get is funny as follows:
Planning
Organization
Measure
Press any key to continue . . .
This is weird. Hope to never write this kind of code!!!
There are several items that need attention here:
You have implemented "fall-through" scenarios, where THREE or TWO+THREE is executed in 2 distinct cases, or ONE+TWO+THREE in all other cases;
I actually do not think the if statements work as intended: [%1%]==[1] should either be [%1%]==[1%] or [%1]==[1];
Should double backslashes be a problem when this script is run from the root, then consider using %__CD__%;
All if statements can be omitted if you just use goto batch%~1 (or similar) and rename your labels; OR
All number labels can be omitted if you just specify the batch to call in the if statements and/or use if-else constructs.
Here are some alternative implementations:
#ECHO OFF
set CURRDIR=%CD%
goto :BATCH%~1 2>NUL
goto :UHOH
:BATCH1
call "%CURRDIR%\PlanningProduct.bat"
goto :DONE
:BATCH2
call "%CURRDIR%\Organization.bat"
goto :DONE
:BATCH3
call "%CURRDIR%\Measure.bat"
goto :DONE
:UHOH
echo Invalid parameter "%~1"
:DONE
pause
#ECHO OFF
set CURRDIR=%CD%
if "%~1"=="1" (
call "%CURRDIR%\PlanningProduct.bat"
) else if "%~1"=="2" (
call "%CURRDIR%\Organization.bat"
) else if "%~1"=="3" (
call "%CURRDIR%\Measure.bat"
) else (
echo Invalid parameter "%~1"
)
pause
#ECHO OFF
set CURRDIR=%CD%
set BAT=
if "%~1"=="1" set BAT=PlanningProduct.bat
if "%~1"=="2" set BAT=Organization.bat
if "%~1"=="3" set BAT=Measure.bat
call "%CURRDIR%\%BAT%" 2>NUL
pause
Does the below produce what you expect?
:ONE
call "%CURRDIR%\PlanningProduct.bat"
GOTO OUT
:TWO
call "%CURRDIR%\Organization.bat"
GOTO OUT
:THREE
call "%CURRDIR%\Measure.bat"
:OUT
pause
After it junps to ONE and executes the call, it is just going to continue on the next line (TWO). A label does not change the execution sequence, it is still going to parse the file line by line unless you jump somewhere.
Either jump away to a specific point:
...
:ONE
call "%CURRDIR%\PlanningProduct.bat"
GOTO DONE
:TWO
...
:DONE
pause
or end the batch:
:ONE
call "%CURRDIR%\PlanningProduct.bat"
pause
GOTO :EOF

Is there a way to pass parameters "by name" (and not by order) to a batch .bat file?

I need to be able to pass parameters to a windows batch file BY NAME (and NOT by order). My purpose here is to give end user the flexibility to pass parameters in any order, and the batch file should still be able to process them.
An example to make my question clearer:
in the command line, user does the following:
somebatchfile.bat originalFile.txt newFile.txt
Inside somebatchfile.bat there is a simple statement to copy the contents of original file (first parameter %1%) to the new file (second parameter %2%). It could be as simple as the following statement:
copy %1% %2%
Now, if user passes the above parameters in reverse order, the result will be far from desirable (very WRONG in fact).
So, is there a way for user to pass parameters by name: e.g. somebatchfile.bat "SOURC=originalFile.txt" "TARGET=newFile.txt" and for script to recognize them and use'em in correct places e.g. copy %SOURCE% %TARGET%?
Thanks,
Yeah you could do something like that though I don't think you can use "=" as a token delimiter. You could use say a colon ":", somebatchfile.bat "SOURC:originalFile.txt" "TARGET:newFile.txt". Here is an example of how you might split the tokens:
#echo off
set foo=%1
echo input: %foo%
for /f "tokens=1,2 delims=:" %%a in ("%foo%") do set name=%%a & set val=%%b
echo name: %name%
echo value: %val%
Running this would produce this:
C:\>test.bat SOURC:originalFile.txt
input: SOURC:originalFile.txt
name: SOURC
value: originalFile.txt
[Edit]
Ok, maybe it was too close to bed time for me last night but looking again this morning, you can do this:
#echo off
set %1
set %2
echo source: %SOURCE%
echo target: %TARGET%
Which would produce this (note that I reversed the source and target on the command line to show they are set and retrieved correctly):
C:\>test.bat "TARGET=newFile.txt" "SOURCE=originalFile.txt"
source: originalFile.txt
target: newFile.txt
Note that %1 and %2 are evaluated before the set so these do get set as environment variables. They must however be quoted on the command line.
A bit late to the party :) This is my suggestion for managing "posix like" options.
For example mybatchscript.bat -foo=foovalue -bar=barvalue -flag
:parseArgs
:: asks for the -foo argument and store the value in the variable FOO
call:getArgWithValue "-foo" "FOO" "%~1" "%~2" && shift && shift && goto :parseArgs
:: asks for the -bar argument and store the value in the variable BAR
call:getArgWithValue "-bar" "BAR" "%~1" "%~2" && shift && shift && goto :parseArgs
:: asks for the -flag argument. If exist set the variable FLAG to "TRUE"
call:getArgFlag "-flag" "FLAG" "%~1" && shift && goto :parseArgs
:: your code here ...
echo FOO: %FOO%
echo BAR: %BAR%
echo FLAG: %FLAG%
goto:eof
..and here the functions that do the job. You should put them in the same batch file
:: =====================================================================
:: This function sets a variable from a cli arg with value
:: 1 cli argument name
:: 2 variable name
:: 3 current Argument Name
:: 4 current Argument Value
:getArgWithValue
if "%~3"=="%~1" (
if "%~4"=="" (
REM unset the variable if value is not provided
set "%~2="
exit /B 1
)
set "%~2=%~4"
exit /B 0
)
exit /B 1
goto:eof
:: =====================================================================
:: This function sets a variable to value "TRUE" from a cli "flag" argument
:: 1 cli argument name
:: 2 variable name
:: 3 current Argument Name
:getArgFlag
if "%~3"=="%~1" (
set "%~2=TRUE"
exit /B 0
)
exit /B 1
goto:eof
Save the file as mybatchscript.bat and run
mybatchscript.bat -bar=barvalue -foo=foovalue -flag
You'll get:
FOO: foovalue
BAR: barvalue
FLAG: TRUE
Other way I quite liked:
set c=defaultC
set s=defaultS
set u=defaultU
:initial
if "%1"=="" goto done
echo %1
set aux=%1
if "%aux:~0,1%"=="-" (
set nome=%aux:~1,250%
) else (
set "%nome%=%1"
set nome=
)
shift
goto initial
:done
echo %c%
echo %s%
echo %u%
Run the following command:
arguments.bat -c users -u products
Will generate the following output:
users
defaultS
products
I wanted to see the possibility of reading named parameter supplied to a batch program. For example :
myBatch.bat arg1 arg2
Reading parameter can be done as follows :
%~1 would be arg1
%~2 would be arg2
Above argument supplied to batch program is easy to read but then each time you execute it, you have to maintain order and remember what arg1 is supposed to have. In order to overcome it, parameter can be supplied as key:value format. And command would look like below :
mybatch.bar key1:value1 key2:value2
Though there is no straight forward way to parse such argument list. I wrote following nested for loop in batch script which will basically parse and create environment variable with key1 as name, and value1 assigned to it. This way you can read all argument supplied using straight forward way of reading environment variable.
#echo off
FOR %%A IN (%*) DO (
FOR /f "tokens=1,2 delims=:" %%G IN ("%%A") DO setLocal %%G=%%H
)
Afterwards, you can use %key1% format to read all argument being supplied.
HTH
Very old question, but I think I found a neat way (with no external dependencies) of passing key=value arguments to a batch file. You can test the method with the following MWE:
#echo off
chcp 65001
rem name this file test.bat and call it with something like:
rem test keyc=foo keyd=bar whatever keya=123 keyf=zzz
setlocal enabledelayedexpansion
set "map=%*"
call :gettoken keya var1
call :gettoken keyb var2
call :gettoken keyc var3
rem replace the following block with your real batch
rem ************************************************
echo:
echo Map is "%map%"
echo Variable var1 is "%var1%"
echo Variable var2 is "%var2%"
echo Variable var3 is "%var3%"
echo:
echo Done.
echo:
pause
rem ************************************************
goto :eof
:gettoken
call set "tmpvar=%%map:*%1=%%"
if "%tmpvar%"=="%map%" (set "%~2=") else (
for /f "tokens=1 delims= " %%a in ("%tmpvar%") do set tmpvar=%%a
set "%~2=!tmpvar:~1!"
)
exit /b
The method is quite:
flexible, because key=value arguments can be mixed with other arguments (such as filenames), and because the name of the variable used to store the value is independent from the name of key
scalable, because it's easy to add keys
robust, because anything passed that is not allowed by defined keys is ignored, and unassigned keys get an empty value (if you want you can easily change this behavior so they get something like null or undefined instead of empty)
A drawback is that it get confused if a key has a name that is part of another key name. So, for example, if you have a key like width, don't define a key like newwidth.
Enjoy.
Take this attempt (pure batch):
set PARAM_0=0
:parameters_parse
set parameter=%~1
if "%parameter%"=="" goto parameters_parse_done
if "%parameter:~0,1%"=="-" (
set ARG_%parameter:~1%="%~2"
shift
shift
goto parameters_parse
)
if "%parameter:~0,1%"=="/" (
set ARG_%parameter:~1%="%~2"
shift
shift
goto parameters_parse
)
set /a PARAM_0=%PARAM_0%+1
set PARAM_%PARAM_0%="%~1"
shift
goto parameters_parse
:parameters_parse_done
rem Insert your script here
and some tests:
call args.bat /bar="Hello World" Test1 -baz "Test test test" /foo=Test1 Test2
echo foo=%ARG_foo%
echo bar=%ARG_bar%
echo baz=%ARG_baz%
echo count=%PARAM_0%
echo 1=%PARAM_1%
echo 2=%PARAM_2%
Outputs:
foo="Test1"
bar="Hello World"
baz="Test test test"
count=2
1="Test1"
2="Test2"
I think you are looking for getopt kind of support in Windows batch scripts which unfortunately doesn't exist in entirety. The closest you can probably get is using GetOpt.btm script. With this then you can execute your script using command:
somebatchfile.bat /SOURC:originalFile.txt /TARGET:newFile.txt
Code:
#echo off
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: GetOpt - Process command line options
::
:: Michael Fross
:: [email]michael#fross.org[/email]
:: [url]http://fross.org[/url]
::
:: This program scans the command line sent to it and sets various
:: environment variables that coorespond to the settings.
::
:: It sets an OPTION_arg variable for each arg on the command line.
:: If a switch, the env var is set to 1. If a value is given via the colon sign,
:: it's set to that value. Note, there can not be any white space around the ':'
::
:: Use "If defined OPTION_arg" or "If %OPTION_arg eq value" to test for options
::
:: It also sets a parameter variable for each paramater entered: PARAM_1 to PARAM_n
:: PARAM_0 is a special value that contains the number of PARAMs. Useful for looping
:: through all of them. For example, do i = 1 to %PARAM_0 by 1 ...
::
:: In your batch file call getopt as:
:: call GetOpt.btm %$
::
:: I also recommend setting setlocal and endlocal in the host batch file so that
:: the option / param variable do not stick around after the host batch files exits.
::
:: Example usage: BatchFile.btm /a /b:22 /longopt Parm1 Parm2 /quotedArg:"long quoted arg"
:: OPTION_a will equal 1.
:: OPTION_b will equal 22
:: OPTION_quotedArg will equal "long quoted arg"
:: OPTION_longopt will eqal 1.
:: PARAM_1 will equal Parm1
:: PARAM_2 will equal Parm2
:: PARAM_0 will be set to the number of parms, so 2 in this case
::
:: To get debug messages, set DEBUG=1. This will give detailed information for each
:: parameter on the command line as getopt loops through the list.
::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Clean up the environment before we get going
unset getopt* OPTION_* PARAM_*
set getopt_ParmCounter=1
:: If in debug mode, kick off the display by showing the number of arguments
if defined DEBUG echo GetOpt is processing %# arguments:
:: Loop through all command line arguments one at a time.
for /L %i in (1,1,%#) do (
if defined DEBUG (echo. %+ echo Scan #%i:)
:: If first character starts with a - or / it must be an option
iff %#instr[0,1,%[%i]] == - .or. %#instr[0,1,%[%i]] == / then
set getopt_Parm=%[%i]
if defined DEBUG echo - Item "%getopt_Parm" is an option.
:: Set the Equal Index to the position of the colon. 0 means none was found
set getopt_EqIdx=%#index[%getopt_Parm,:]
:: Display the index position of the colon
if defined DEBUG .AND. %getopt_EqIdx GE 0 echo - Found colon at index position "%getopt_EqIdx"
:: If the index is GE 0 then we must have a colon in the option.
:: set the OPTION value to the stuff to the right of the colon
iff %getopt_EqIdx ge 0 then
set getopt_ParmName=%#instr[2, %#Dec[%getopt_EqIdx] , %getopt_Parm]
if defined DEBUG echo - ParmName = "%getopt_ParmName"
set getopt_ParmValue=%#right[%#eval[-%getopt_EqIdx-1],%getopt_Parm]
if defined DEBUG echo - Parmvalue = "%getopt_ParmValue"
set OPTION_%getopt_ParmName=%getopt_ParmValue
else
:: This is a flag, so simply set the value to 1
if defined DEBUG echo - No colon found in "%getopt_Parm"
set getopt_ParmName=%#right[%#Dec[%#len[%getopt_Parm]],%getopt_Parm]
set getopt_ParmValue=1
if defined DEBUG echo - ParmName = "%getopt_ParmName"
set OPTION_%getopt_ParmName=%getopt_ParmValue
endiff
:: Regardless if there was a value or not, display what is going to occur
if defined DEBUG echo - Setting Variable OPTION_%getopt_ParmName=%getopt_ParmValue
else
:: There was no / or - found, therefore this must be a paramater, not an option
if defined DEBUG echo - "%[%i]" is a parameter, not an option
set PARAM_%getopt_ParmCounter=%[%i]
set PARAM_0=%getopt_ParmCounter
if defined DEBUG echo - Updating Number of Parms. PARAM_0=%PARAM_0
if defined DEBUG echo - Setting Variable PARAM_%getopt_ParmCounter = %[%i]
set getopt_ParmCounter=%#Inc[%getopt_ParmCounter]
endiff
)
:: Display additional information
iff defined DEBUG then
echo.
echo There were %PARAM_0 parameters found. Setting PARAM_0=%PARAM_0
echo.
echo GetOpt has completed processing %# arguments. Ending Execution.
endiff
:: Perform cleanup
unset getopt_*
My gosh people; You're overthinking this! :)
OP's CMD args are all in the form "[VarName]=[Something]"
So the 1st line could simply be FOR %%_ IN (%*) DO SET "%%~_"
or in nicer looking code
FOR %%_ IN (%*) DO SET "%%~_"
That said here is a more complete script example where you could just put all of your script within the :Main function
#( Setlocal
ECHO OFF
FOR %%_ IN (%*) DO SET "%%~_"
)
CALL :Main
( ENDLOCAL
EXIT /B )
:Main
REM Your code goes here.
REM Your code goes here.
REM Your code goes here.
REM Your code goes here.
GOTO :EOF
:parse
IF "%~1"=="" GOTO endparse
ECHO "%~1"| FIND /I "=" && SET "%~1"
SHIFT /1
GOTO parse
:endparse
This code checks all the parameters, strips all the outer quotes, and if equal sign is present, sets variable to value.
Use it like this:
yourbatch.bat "foo=bar" "foo2=bar2"
based on this answer: Using parameters in batch files at DOS command line, and edited in response to the edit attempt by D.Barev

Resources