Option to optionally analyze Windows Bat files

I need my bat file to accept a few optional named arguments.

mycmd.bat man1 man2 -username alice -otheroption 

For example, my command has 2 required parameters and two optional parameters (-name), which have the value of the alice and -theroption arguments:

I would like these values ​​to be bound to variables.

Just by calling everyone who has already decided this. To a person these bat files hurt.

+68
batch-file
October 20 '10 at 0:05
source share
5 answers

Although I tend to agree with the @AlekDavis comment , there are still several ways to do this in the NT shell.

I would use the SHIFT command and IF conditional branching, something like this ...

 @ECHO OFF SET man1=%1 SET man2=%2 SHIFT & SHIFT :loop IF NOT "%1"=="" ( IF "%1"=="-username" ( SET user=%2 SHIFT ) IF "%1"=="-otheroption" ( SET other=%2 SHIFT ) SHIFT GOTO :loop ) ECHO Man1 = %man1% ECHO Man2 = %man2% ECHO Username = %user% ECHO Other option = %other% REM ...do stuff here... :theend 
+98
Oct 20 2018-10-10
source share
β€” -

The selected answer works, but it may use some improvement.

  • Parameters should probably be initialized with default values.
  • It would be nice to save% 0, as well as the necessary arguments% 1 and% 2.
  • It becomes painful to have an IF block for each parameter, especially as the number of options increases.
  • It would be nice to have a simple and concise way to quickly determine all the parameters and default values ​​in one place.
  • It would be useful to maintain autonomous parameters that serve as checkboxes (no value after the value).
  • We do not know if arg is enclosed in quotation marks. We also do not know if the arg value was passed using escaped characters. It is better to access the argument using% ~ 1 and enclose the assignment in quotation marks. Then the party can rely on the absence of closed quotes, but special characters are still generally safe without exiting. (This is not bullet proof, but it copes with most situations).

My solution is based on creating an OPTIONS variable that defines all the parameters and their default values. OPTIONS are also used to check if the delivery option is valid. A huge amount of code is saved by simply storing the parameter values ​​in variables named in the same way as the parameter. The amount of code is constant regardless of how many options are defined; only the definition of OPTIONS should change.

EDIT . In addition, the loop code must change if the number of required positional arguments changes. For example, often when all the arguments are called, in this case you want to analyze the arguments starting from position 1, not 3. Thus, inside the loop: all 3 become 1 and 4 become 2.

 @echo off setlocal enableDelayedExpansion :: Define the option names along with default values, using a <space> :: delimiter between options. I'm using some generic option names, but :: normally each option would have a meaningful name. :: :: Each option has the format -name:[default] :: :: The option names are NOT case sensitive. :: :: Options that have a default value expect the subsequent command line :: argument to contain the value. If the option is not provided then the :: option is set to the default. If the default contains spaces, contains :: special characters, or starts with a colon, then it should be enclosed :: within double quotes. The default can be undefined by specifying the :: default as empty quotes "". :: NOTE - defaults cannot contain * or ? with this solution. :: :: Options that are specified without any default value are simply flags :: that are either defined or undefined. All flags start out undefined by :: default and become defined if the option is supplied. :: :: The order of the definitions is not important. :: set "options=-username:/ -option2:"" -option3:"three word default" -flag1: -flag2:" :: Set the default option values for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B" :loop :: Validate and store the options, one at a time, using a loop. :: Options start at arg 3 in this example. Each SHIFT is done starting at :: the first option so required args are preserved. :: if not "%~3"=="" ( set "test=!options:*%~3:=! " if "!test!"=="!options! " ( rem No substitution was made so this is an invalid option. rem Error handling goes here. rem I will simply echo an error message. echo Error: Invalid option %~3 ) else if "!test:~0,1!"==" " ( rem Set the flag option using the option name. rem The value doesn't matter, it just needs to be defined. set "%~3=1" ) else ( rem Set the option value using the option as the name. rem and the next arg as the value set "%~3=%~4" shift /3 ) shift /3 goto :loop ) :: Now all supplied options are stored in variables whose names are the :: option names. Missing options have the default value, or are undefined if :: there is no default. :: The required args are still available in %1 and %2 (and %0 is also preserved) :: For this example I will simply echo all the option values, :: assuming any variable starting with - is an option. :: set - :: To get the value of a single parameter, just remember to include the `-` echo The value of -username is: !-username! 

There really isn’t much code here. Most of the code above is comments. Here is the same code, no comment.

 @echo off setlocal enableDelayedExpansion set "options=-username:/ -option2:"" -option3:"three word default" -flag1: -flag2:" for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B" :loop if not "%~3"=="" ( set "test=!options:*%~3:=! " if "!test!"=="!options! " ( echo Error: Invalid option %~3 ) else if "!test:~0,1!"==" " ( set "%~3=1" ) else ( set "%~3=%~4" shift /3 ) shift /3 goto :loop ) set - :: To get the value of a single parameter, just remember to include the `-` echo The value of -username is: !-username! 


This solution provides Unix style arguments in the Windows package. This is not the norm for Windows - a batch usually has parameters preceding the required arguments, and the parameters are prefixed with / .

The methods used in this solution are easily adaptable for Windows style options.

  • The analysis loop always searches for a parameter in %1 , and it continues until arg 1 starts with /
  • Note that SET assignments must be enclosed in quotation marks if the name begins with / .
    SET /VAR=VALUE fails SET "/VAR=VALUE" works. In any case, I already do this in my decision.
  • Windows standard style excludes the possibility of the first argument value starting with / . This restriction can be eliminated by using the implicit // option, which serves as a signal to exit the parsing cycle. For option // nothing will be saved. "




Update 2015-12-28: Support ! in parameter values

In the above code, each argument expands when slow expansion is enabled, which means that ! most likely deprived, or something like !var! expands. Alternatively, ^ can also be deleted if present ! . The following small modification of uncommented code removes the restriction, so ! and ^ are stored in parameter values.

 @echo off setlocal enableDelayedExpansion set "options=-username:/ -option2:"" -option3:"three word default" -flag1: -flag2:" for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B" :loop if not "%~3"=="" ( set "test=!options:*%~3:=! " if "!test!"=="!options! " ( echo Error: Invalid option %~3 ) else if "!test:~0,1!"==" " ( set "%~3=1" ) else ( setlocal disableDelayedExpansion set "val=%~4" call :escapeVal setlocal enableDelayedExpansion for /f delims^=^ eol^= %%A in ("!val!") do endlocal&endlocal&set "%~3=%%A" ! shift /3 ) shift /3 goto :loop ) goto :endArgs :escapeVal set "val=%val:^=^^%" set "val=%val:!=^!%" exit /b :endArgs set - :: To get the value of a single parameter, just remember to include the `-` echo The value of -username is: !-username! 
+56
Nov 17 '11 at 5:33
source share

If you want to use optional arguments but not named arguments, then this approach worked for me. I think it’s much easier to use code for this.

 REM Get argument values. If not specified, use default values. IF "%1"=="" ( SET "DatabaseServer=localhost" ) ELSE ( SET "DatabaseServer=%1" ) IF "%2"=="" ( SET "DatabaseName=MyDatabase" ) ELSE ( SET "DatabaseName=%2" ) REM Do work ECHO Database Server = %DatabaseServer% ECHO Database Name = %DatabaseName% 
+17
Mar 31 '14 at 9:52
source share

Here is the argument parser. You can mix any string arguments (left unchanged) or escaped options (single pairs or option / value pairs). To verify this, uncomment the last 2 statements and do the following:

 getargs anystr1 anystr2 /test$1 /test$2=123 /test$3 str anystr3 

The "_SEP_=/" character is defined as "_SEP_=/" , override if necessary.

 @echo off REM Command line argument parser. Format (both "=" and "space" separators are supported): REM anystring1 anystring2 /param1 /param2=value2 /param3 value3 [...] anystring3 anystring4 REM Returns enviroment variables as: REM param1=1 REM param2=value2 REM param3=value3 REM Leading and traling strings are preserved as %1, %2, %3 ... %9 parameters REM but maximum total number of strings is 9 and max number of leading strings is 8 REM Number of parameters is not limited! set _CNT_=1 set _SEP_=/ :PARSE if %_CNT_%==1 set _PARAM1_=%1 & set _PARAM2_=%2 if %_CNT_%==2 set _PARAM1_=%2 & set _PARAM2_=%3 if %_CNT_%==3 set _PARAM1_=%3 & set _PARAM2_=%4 if %_CNT_%==4 set _PARAM1_=%4 & set _PARAM2_=%5 if %_CNT_%==5 set _PARAM1_=%5 & set _PARAM2_=%6 if %_CNT_%==6 set _PARAM1_=%6 & set _PARAM2_=%7 if %_CNT_%==7 set _PARAM1_=%7 & set _PARAM2_=%8 if %_CNT_%==8 set _PARAM1_=%8 & set _PARAM2_=%9 if "%_PARAM2_%"=="" set _PARAM2_=1 if "%_PARAM1_:~0,1%"=="%_SEP_%" ( if "%_PARAM2_:~0,1%"=="%_SEP_%" ( set %_PARAM1_:~1,-1%=1 shift /%_CNT_% ) else ( set %_PARAM1_:~1,-1%=%_PARAM2_% shift /%_CNT_% shift /%_CNT_% ) ) else ( set /a _CNT_+=1 ) if /i %_CNT_% LSS 9 goto :PARSE set _PARAM1_= set _PARAM2_= set _CNT_= rem getargs anystr1 anystr2 /test$1 /test$2=123 /test$3 str anystr3 rem set | find "test$" rem echo %1 %2 %3 %4 %5 %6 %7 %8 %9 :EXIT 
+1
Dec 14 '16 at 23:02
source share

As soon as I wrote a program that processes short (-h), long (--help) and optional arguments in a batch file. These methods include:

  • arguments without options, followed by argument arguments.

  • shift operator for those options that do not have arguments like "-help".

  • two time shift operators for those parameters that require an argument.

  • swipe the label to process all command line arguments.

  • Exit the script and stop processing for those parameters that do not require additional actions, such as "-help".

  • Wrote help functions for user convenience

Here is my code.

 set BOARD= set WORKSPACE= set CFLAGS= set LIB_INSTALL=true set PREFIX=lib set PROGRAM=install_boards :initial set result=false if "%1" == "-h" set result=true if "%1" == "--help" set result=true if "%result%" == "true" ( goto :usage ) if "%1" == "-b" set result=true if "%1" == "--board" set result=true if "%result%" == "true" ( goto :board_list ) if "%1" == "-n" set result=true if "%1" == "--no-lib" set result=true if "%result%" == "true" ( set LIB_INSTALL=false shift & goto :initial ) if "%1" == "-c" set result=true if "%1" == "--cflag" set result=true if "%result%" == "true" ( set CFLAGS=%2 if not defined CFLAGS ( echo %PROGRAM%: option requires an argument -- 'c' goto :try_usage ) shift & shift & goto :initial ) if "%1" == "-p" set result=true if "%1" == "--prefix" set result=true if "%result%" == "true" ( set PREFIX=%2 if not defined PREFIX ( echo %PROGRAM%: option requires an argument -- 'p' goto :try_usage ) shift & shift & goto :initial ) :: handle non-option arguments set BOARD=%1 set WORKSPACE=%2 goto :eof :: Help section :usage echo Usage: %PROGRAM% [OPTIONS]... BOARD... WORKSPACE echo Install BOARD to WORKSPACE location. echo WORKSPACE directory doesn't already exist! echo. echo Mandatory arguments to long options are mandatory for short options too. echo -h, --help display this help and exit echo -b, --boards inquire about available CS3 boards echo -c, --cflag=CFLAGS making the CS3 BOARD libraries for CFLAGS echo -p. --prefix=PREFIX install CS3 BOARD libraries in PREFIX echo [lib] echo -n, --no-lib don't install CS3 BOARD libraries by default goto :eof :try_usage echo Try '%PROGRAM% --help' for more information goto :eof 
+1
Dec 19 '17 at 12:36 on
source share



All Articles