Processing command line options & parameters in a batch file

  • This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

nchernoff

Administrator
Staff member
May 16, 2008
42
2
#1
Migrated From JP Software Wiki

Overview

There are often times one wishes to process command line options and parameters in a consistent way, and not duplicate parsing in every bath file. GetOpt is a common and freely available option parser and this batch file attempts to mimic a few of it's basic functions within the limitations of TakeCommand.

There are two main categories of command line items.

  1. Program Parameters. These are inputs for the progam and are entered in on the command line without switch characters. For example, the command "copy a b" has two parameters, a and b.
  2. Program Switches. These typically change the way the command works. They are usually prefaced with a dash (-) or a slash (/). For example, the command "copy /q a b" has one boolean switch. Switches may also have values associated with them, so the command "copy /q /s:1 a b" is valid.
The usage of GetOpt.btm is fairly simple.
  • If you wish to see a lot of debug information on what's going on, execute "set debug=1" before running.
  • Call getopt.btm in your batch file by executing: call GetOpt.btm %$
  • OPTION_x will be set for each option where x is the option name. If the option equals a value, it will be set that value, if not it will be set to 1.
  • PARAM_x will be a sequential number each equal to the parameter value.
  • PARAM_0 is a special case and will equal the number of parameters entered
  • It is highly recommended that your batch file by enclosed by "SetLocal" and "EndLocal" commands. This will prevent the variables set in GetOpt from living after your program has terminated. You could also add:
    unset getopt* OPTION_* PARAM_*
    at the end of your program to clean up the variables that are set.


I hope that the following example may help illustrate.

Examples:
Code:
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
So, as an example, to process all items listed on the command line you could:

Code:
call GetOpt.btm %$
do i=1 to %PARM_0 by 1
  echo Processing %PARM_$i
  gosub ProcessParm
enddo
Or, to perform an action based on a boolean switch you could:

Code:
call GetOpt.btm %$
iff defined %OPTION_v then
  gosub DisplayVerion
endiff
I would appreciate any comments or suggestions I could use to improve this program.

Michael Fross
michael _at_ fross _dot_ org


GetOpt.btm

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_*
 
#2
GetOpt.btm - Processing command line options & parameters in a batch file

For reasons unknown, I the message below could not be delivered as a
response to tc_tips@jpsoft.com:

Steve Fabian wrote:
| nchernoff wrote:
|| Migrated From JP Software Wiki
||
|| *Overview*
|
| PLEASE think of us whose mail client returns the "subject" in small,
| low contrast font - it is NOT legible! It is not part of the message
| body, either. It is NOT suitable to use as a TITLE for an ARTICLE.
|
| To find out the subject of the message outside of the browser, I have
| to change screen resolution (yes, I do have a hotkey to do that), but
| that increases text size so most lines wrap. Now I have to change
| screensize back. Lots of wasted time.
--
Steve
 
#3
Hello everyone,

I'm not sure if anyone uses this, but I've made a few tweaks to this over time and thought I would post an updated version. I'm also going to post another script I've written that calls this so I thought I would post getopt.btm first.

I use mercurial for source code management. You can always get the latest version of GetOpt.btm at:

or if you use Mercurial, you can clone the repository using:


I've been using this for years and it meets my needs very well. If you have ideas or questions, please let me know. I've love to hear what folks think (good and bad).

Thanks,
Fross

Code:
@echo off
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: GetOpt - Process command line options
:: 
:: Michael Fross
:: michael@fross.org
:: http://fross.org
::
:: This program scans the command line sent to it and sets various 
:: environment variables that coorespond to the settings.
::
:: In your batch file call getopt as:
::call GetOpt.btm %$
::
::The %$ sends the command line to the getopt function.  Use full path if needed
::
:: Options:
:: 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 ':'
::
:: To test for a specific option, use "If defined OPTION_arg" or "If %OPTION_arg eq value" 
:: For example: getopt.btm -v filename
:: "If defined OPTION_v echo Verbose is set"
:: 
:: Parameters:
:: Getopt 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 ...
::
:: 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
:: item 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
iff defined DEBUG then
echo ---GetOpt Debug Messages Follow ----------------------------------------------
echo GetOpt is processing %# arguments:
endiff
 
:: Loop through all command line arguments one at a time.
do i = 1 to %#
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 Colon Index to the position of the colon.  0 means none was found
set getopt_ColonIdx=%@index[%getopt_Parm,:]
 
:: Display the index position of the colon
iff defined DEBUG .AND. %getopt_ColonIdx GE 0 then
echo  - Found colon at index position: %getopt_ColonIdx
endiff
 
:: 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_ColonIdx ge 0 then
set getopt_ParmName=%@instr[2, %@Dec[%getopt_ColonIdx] , %getopt_Parm]
if defined DEBUG echo  - ParmName  = "%getopt_ParmName"
set getopt_ParmValue=%@right[%@eval[-%getopt_ColonIdx-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
enddo
 
:: Perform cleanup
unset getopt_* 
 
:: Display summary 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.
echo ---End GetOpt Debug Messages -------------------------------------------------
endiff
 
#4
This reminds me of getopts, a 4DOS/4NT/TCC option parser which I wrote in 2001:

Code:
GETOPTS.BTM version 1.1 - DOCUMENTATION
 
SUMMARY
 
  The purpose of GETOPTS.BTM is to allow 4DOS batch files to support
  Unix-style option switches on the command line. The idea is that a
  4DOS batch file can "call" GETOPTS, which locates and parses each
  option and sets environment variables, while the parent batch file
  determines which switches are allowed and handles other details. I
  wrote GETOPTS to mimic, within reason, the operation of "getopts"
  in the Unix/GNU/Linux environment.
 
  GETOPTS.BTM was written by Eric Pement ([eaddress redacted]) in
  December 2001. Your feedback and suggestions for improvement are
  welcome. It is freely offered to the 4DOS user community under the
  terms of the GNU General Public License (version 2).
 
SYNTAX:
 
  When GETOPTS is active, the following command lines are equivalent:
 
      cmd -a -b -C -w foo -W "one two" word1 word2
      cmd -ba -wfoo -C -W"one two" -- word1 word2
      cmd word1 word2 -abCwfoo -W"one two"
      cmd -W "one two" word1 -bw foo word2 -aC
 
  Given the example above, GETOPTS will create and return the
  following environment variables to the parent batch file:
 
      OPTIONS=a b C!    - a list of character switches used
      STRINGS=LC_w UC_W  - a list of string switches used
      LC_W=foo          - each string switch has a separate variable
      UC_W="one two"    - case-sensitivity is kept by LC_ or UC_
 
  Moreover, the command tail %& will be reset to "word1 word2" since
  all the options and option-arguments have been stripped out.
 
FEATURES SUPPORTED:
 
  * Position-independent switch clustering
      "-a -b -c" equals "-ac -b" equals "-c -ba" equals "-bac".
 
  * 3 types of switches:
      Character switches, String switches, and Numeric options.
 
  * Case-sensitive character switches
      Character switches are one character (a-z or A-Z) which never
      take an argument or parameter. They are case-sensitive, meaning
      that "-d" and "-D" are seen as different switches.
 
  * Case-sensitive string switches
      String switches are one character (a-z or A-Z) which MUST take
      an argument or parameter. Thus, -f and -F may accept different
      arguments which may be passed as '-fhello' or '-F goodbye'.
      Multi-word arguments are permitted if they are enclosed in
      double quotes, such as '-g "one or more words"'.
 
  * Numeric options
      Numeric options may be permitted or forbidden. If permitted,
      -123 will set N=123, and --456 will set N=-456.
 
  * Switches and argument removed from the command tail
      Under GETOPTS, all switches and switch parameters on the
      command line are placed into appropriate environment variables
      (see SYNTAX: for examples, above). The switches are then
      removed from the command tail (%&). If the batch file executes
      external utilities, the utility's own option syntax can be used
      (e.g., /opt1, opt2:opt3, word=opt4, etc.).
 
  * Halt on invalid options
      The parent batch file contains a list of permissible letters for
      character and string options, and tells whether numeric options
      are allowed. The GETOPTS batch file first checks the list itself
      and then checks each option on the command-tail for validity.
      GETOPTS will halt if it detects invalid options, but it can be
      set to "pass" invalid options through instead.
 
  * Switch termination
      To permit processing filenames which begin with leading
      hyphens, the switch "--" terminates switch processing, and the
      rest of the command tail is returned untouched to the parent
      batch file. Further, a single hyphen "-" by itself is passed
      without modification to the command tail.
 
[... rest omitted ...]
Klaus Meinhard was kind enough to give it an award on his web site, http://www.4dos.info , and I continue to use getopts.btm to this day, virtually unmodified.

I will take a look at your version !!

--
Eric Pement
 
#5
Thanks Eric. If I would have known there was another one out there I would probably never have written it! (Although I remember I was sitting on a plane and bored...)

If you have any ideas or suggestions please let me know. I use this little guy in almost every batch file I write.

Also, setting DEBUG=1 before running it will give you a pretty good idea of what's going on inside. See below for an example.

Thanks,

Michael

Code:
C:\Users\Michael>set DEBUG=1
 
C:\Users\Michael>C:\utils\GetOpt.btm /a -b /longopt /evenlonger:123 cmdline1 -q cmdline2
 
---GetOpt Debug Messages Follow ----------------------------------------------
GetOpt is processing 7 arguments:
 
Scan #1:
 - Item "/a" is an option.
 - No colon found in "/a"
 - ParmName = "a"
 - Setting Variable OPTION_a=1
 
Scan #2:
 - Item "-b" is an option.
 - No colon found in "-b"
 - ParmName = "b"
 - Setting Variable OPTION_b=1
 
Scan #3:
 - Item "/longopt" is an option.
 - No colon found in "/longopt"
 - ParmName = "longopt"
 - Setting Variable OPTION_longopt=1
 
Scan #4:
 - Item "/evenlonger:123" is an option.
 - Found colon at index position: 11
 - ParmName  = "evenlonger"
 - Parmvalue = "123"
 - Setting Variable OPTION_evenlonger=123
 
Scan #5:
 - "cmdline1" is a parameter, not an option
 - Updating Number of Parms.  PARAM_0=1
 - Setting Variable PARAM_1 = cmdline1
 
Scan #6:
 - Item "-q" is an option.
 - No colon found in "-q"
 - ParmName = "q"
 - Setting Variable OPTION_q=1
 
Scan #7:
 - "cmdline2" is a parameter, not an option
 - Updating Number of Parms.  PARAM_0=2
 - Setting Variable PARAM_2 = cmdline2
 
There were 2 parameters found.  Setting PARAM_0=2
 
GetOpt has completed processing 7 arguments.  Ending Execution.
---End GetOpt Debug Messages -------------------------------------------------