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
orundefined
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
精彩评论