I need to pass an ID and a password to a batch file at the time of running rather than hardcoding them into the file.
Here\'s what the command line looks like:
Inspired by an answer elsewhere by @Jon, I have crafted a more general algorithm for extracting named parameters, optional values, and switches.
Let us say that we want to implement a utility foobar
. It requires an initial command. It has an optional parameter --foo
which takes an optional value (which cannot be another parameter, of course); if the value is missing it defaults to default
. It also has an optional parameter --bar
which takes a required value. Lastly it can take a flag --baz
with no value allowed. Oh, and these parameters can come in any order.
In other words, it looks like this:
foobar [--foo []] [--bar ] [--baz]
Here is a solution:
@ECHO OFF
SETLOCAL
REM FooBar parameter demo
REM By Garret Wilson
SET CMD=%~1
IF "%CMD%" == "" (
GOTO usage
)
SET FOO=
SET DEFAULT_FOO=default
SET BAR=
SET BAZ=
SHIFT
:args
SET PARAM=%~1
SET ARG=%~2
IF "%PARAM%" == "--foo" (
SHIFT
IF NOT "%ARG%" == "" (
IF NOT "%ARG:~0,2%" == "--" (
SET FOO=%ARG%
SHIFT
) ELSE (
SET FOO=%DEFAULT_FOO%
)
) ELSE (
SET FOO=%DEFAULT_FOO%
)
) ELSE IF "%PARAM%" == "--bar" (
SHIFT
IF NOT "%ARG%" == "" (
SET BAR=%ARG%
SHIFT
) ELSE (
ECHO Missing bar value. 1>&2
ECHO:
GOTO usage
)
) ELSE IF "%PARAM%" == "--baz" (
SHIFT
SET BAZ=true
) ELSE IF "%PARAM%" == "" (
GOTO endargs
) ELSE (
ECHO Unrecognized option %1. 1>&2
ECHO:
GOTO usage
)
GOTO args
:endargs
ECHO Command: %CMD%
IF NOT "%FOO%" == "" (
ECHO Foo: %FOO%
)
IF NOT "%BAR%" == "" (
ECHO Bar: %BAR%
)
IF "%BAZ%" == "true" (
ECHO Baz
)
REM TODO do something with FOO, BAR, and/or BAZ
GOTO :eof
:usage
ECHO FooBar
ECHO Usage: foobar ^ [--foo [^]] [--bar ^] [--baz]
EXIT /B 1
SETLOCAL
so that the variables don't escape into the calling environment.SET FOO=
, etc. in case someone defined them in the calling environment.%~1
to remove quotes.IF "%ARG%" == ""
and not IF [%ARG%] == []
because [
and ]
don't play will at all with values ending in a space.SHIFT
inside an IF
block, the current args such as %~1
don't get updated because they are determined when the IF
is parsed. You could use %~1
and %~2
inside the IF
block, but it would be confusing because you had a SHIFT
. You could put the SHIFT
at the end of the block for clarity, but that might get lost and/or confuse people as well. So "capturing" %~1
and %~1
outside the block seems best.IF NOT "%ARG:~0,2%" == "--"
.SHIFT
when you use one of the parameters.SET FOO=%DEFAULT_FOO%
is regrettable, but the alternative would be to add an IF "%FOO%" == "" SET FOO=%DEFAULT_FOO%
outside the IF NOT "%ARG%" == ""
block. However because this is still inside the IF "%PARAM%" == "--foo"
block, the %FOO%
value would have been evaluated and set before you ever entered the block, so you would never detect that both the --foo
parameter was present and also that the %FOO%
value was missing.ECHO Missing bar value. 1>&2
sends the error message to stderr.ECHO:
or one of the variations.