Is there any documentation/discussion, either in DosTips or elsewhere, on how to implement your own switches/options in a batch script? Such as, the best way to validate a switch inputted by the user, how to test which switch is used, etc...
Thanks
Help creating and implementing "switches" or "options" in custom batch script
Moderator: DosItHelp
-
- Posts: 31
- Joined: 23 Nov 2015 09:34
Re: Help creating and implementing "switches" or "options" in custom batch script
Not sure if this is what you are looking for.
foolproof counting of arguments
foolproof counting of arguments
-
- Posts: 31
- Joined: 23 Nov 2015 09:34
Re: Help creating and implementing "switches" or "options" in custom batch script
Not so much validation, but simply an efficient reliable way to check with switches were used and then perform the appropriate action based on the user's input. Example: a custom script to search for file on a computer, where the user appends "/x" which means the user wants to export the search results. ...what's the best way to handle that switch to execute the code associated with that option?Squashman wrote:Not sure if this is what you are looking for.
foolproof counting of arguments
Re: Help creating and implementing "switches" or "options" in custom batch script
Check out my StackOverflow answer to a question about Windows Bat file optional argument parsing.
I have successfully used that technique in a number of scripts, including my JREPL.BAT regular expression find and replace utility
Dave Benham
I have successfully used that technique in a number of scripts, including my JREPL.BAT regular expression find and replace utility
Dave Benham
Re: Help creating and implementing "switches" or "options" in custom batch script
Yes. I was actually going to post the link to your old GetTimeStamp.bat, which I believes uses that same technique. Your solution on SO, seems like the better answer. There is too many possibilities for failure in the selected answer.dbenham wrote:Check out this StackOverflow answer to a question about Windows Bat file optional argument parsing.
Dave Benham
-
- Posts: 31
- Joined: 23 Nov 2015 09:34
Re: Help creating and implementing "switches" or "options" in custom batch script
Awesome, I shall check out that SO answer.
Re: Help creating and implementing "switches" or "options" in custom batch script
I think I have a good solution going.
Here’s the parameter system I use, or at least what I would use if I ever had any good ideas for large projects
The boilerplate is rather bulky, but I would expect nothing less than heavy-duty if you’re looking into clean argument handling.
This is this the non-minified JScript code.
Example usage:
Here’s the parameter system I use, or at least what I would use if I ever had any good ideas for large projects
Code: Select all
::: !my_cmd! first second [third] [/key:value] [/nintendo]
:::
::: Synopsis:
::: These auxiliary functions streamline the process of argument parsing and validation.
:::
::: Description:
::: The heavy lifting is done by an external temporary JScript file. It processes the
::: batch arguments by spitting out an organised copy of each of the positional and
::: optional arguments into their own separate variables. This means you can specify
::: arguments in any order on the command line without having to worry about separating
::: positional arguments from optional arguments.
:::
::: The original %1 variables are preserved. Denote named arguments with either '/' or
::: '-'. For key-value pairs use ':' or '=' as the delimiter.
:::
@echo off
setlocal EnableDelayedExpansion
goto :main
:arg_parser FileName
if "%~1"=="" exit /b 5
set "_arg_file21234="%~1""
if not exist %_arg_file21234% exit /b 53
for /f "tokens=1,* delims==" %%I in (' 2^>nul set arg[ ') do (set "%%~I=")
set "arg[]=1"
<%_arg_file21234% set /p "arg[*]="
setlocal EnableDelayedExpansion
>%_arg_file21234% echo var args=WScript.Arguments;for^(var argkList=[],pC=0,nC=0,i=0;i^<args.Length;i++^){var arg=args.Item^(i^);if^(^^!arg.length^|^|'/-'.indexOf^(arg.charAt^(0^)^)^<0^){WScript.Echo^('arg['+ ++pC+']='+arg^)}else{var a=arg.indexOf^(':'^),b=arg.indexOf^('='^);var d=a*b^<0?Math.max^(a,b^):Math.min^(a,b^);argk=^(d^<0?arg.slice^(1^):arg.slice^(1,d^)^).toLowerCase^(^);argv=d^<0?'1':arg.slice^(d+1^);WScript.Echo^("arg['"+argk+"']="+argv^);if^(^^!^(new RegExp^('^^^^(?:'+argkList.join^('^|'^)+'^)$'^).test^(argk^)^)^){argkList.push^(argk^);nC++}}}WScript.Echo^('arg[#]='+i+'\narg[#p]='+pC+'\narg[#q]='+nC^)
endlocal
for /f "delims=" %%I in (' cscript.exe /nologo %_arg_file21234% %arg[*]% ') do (set %%I)
del %_arg_file21234%
set "_arg_file21234="
goto :eof
:arg_validate
setlocal EnableDelayedExpansion
REM Example argument validation:
REM Accept 2-3 positional arguments, an optional 'key' key-value pair and an optional 'nintendo' switch
if not defined arg[] exit /b 5
if not defined arg[1] echo ArgErr: takes from 2-3 positional arguments but none were given& exit /b 1
if not defined arg[2] echo ArgErr: takes from 2-3 positional arguments but 1 was given& exit /b 1
if defined arg[4] echo ArgErr: takes from 2-3 positional arguments but %arg[#p]% were given& exit /b 1
set "expected_keys=key:nintendo"
for /f "useback tokens=1,* delims==" %%I in (` 2^>nul set arg[' `) do (
set "argk=%%~I"
set "argk=!argk:~5,-2!"
echo(!argk!| findstr "^%expected_keys::=$ ^%$" >nul || (
echo ArgErr: got an unexpected named argument '!argk!'
exit /b 1
)
)
endlocal
exit /b 0
:help
setlocal EnableDelayedExpansion
set "my_cmd=%~n0"
for /f "tokens=1,* delims=:" %%1 in (' findstr /n "^:::" "%~f0" ') do echo(%%2
endlocal
goto :eof
:main
set "arg[0]=%temp%\%~nx0_arg-parse.tmp.js"
>"%arg[0]%" echo(%* & call :arg_parser "%arg[0]%"
if defined arg['?'] call :help & exit /b 0
call :arg_validate >&2 || exit /b 1
REM Batch program starts here
echo Argument count: %arg[#]% &REM this does not necessarily equal %arg[#p]% + %arg[#q]%. (Hint: consider duplicate switches)
echo Positional argument count: %arg[#p]%
echo Named argument count: %arg[#q]% &REM number of unique named arguments given
echo All args: %arg[*]% &REM should be the same as %*
for /l %%I in (1 1 %arg[#p]%) do echo Argument %%I is !arg[%%I]!
if defined arg['key'] echo The named argument 'key' = %arg['key']%
echo(
set arg[
This is this the non-minified JScript code.
Code: Select all
var args = WScript.Arguments
for (var argkList = [], pC = 0, nC = 0, i = 0; i < args.Length; i++) {
var arg = args.Item(i)
if (!arg.length || '/-'.indexOf(arg.charAt(0)) < 0) {
WScript.Echo('arg[' + ++pC + ']=' + arg)
} else {
var a = arg.indexOf(':'), b = arg.indexOf('=')
var d = a * b < 0 ? Math.max(a, b) : Math.min(a, b)
argk = (d < 0 ? arg.slice(1) : arg.slice(1, d)).toLowerCase()
argv = d < 0 ? '1' : arg.slice(d + 1)
WScript.Echo("arg['" + argk + "']=" + argv)
// ignore duplicate switches
if (!(new RegExp('^(?:' + argkList.join('|') + ')$').test(argk))) {
argkList.push(argk)
nC++
}
}
}
WScript.Echo(
'arg[#]=' + i +
'\narg[#p]=' + pC +
'\narg[#q]=' + nC
)
Code: Select all
C:\>file.bat near /key:"value"
ArgErr: takes from 2-3 positional arguments but 1 was given
C:\>file.bat near far /key:"value"
Argument count: 3
Positional argument count: 2
Named argument count: 1
All args: near far /key:"value"
Argument 1 is near
Argument 2 is far
The named argument 'key' = value
arg[#p]=2
arg[#q]=1
arg[#]=3
arg['key']=value
arg[*]=near far /key:"value"
arg[1]=near
arg[2]=far
arg[]=1
C:\>