Find value of command line argument in batch file - batch-file

I am passing a list of arguments while running a batch file and need the value of a particular argument -logdir to set some dir path in my batch file. How can I first check if the -logdir is passed as argument and if it is passed get its value and set it in a variable.
I am running it like:
test.bat -env test1 -logdir C:\Users\...\log -userhome ... -log ...
and many more arguments. These arguments can be passed in different order.
I am able to fetch the list of arguments passed using below.
set argCount=0
for %%x in (%*) do set /A argCount+=1
echo Number of processed arguments: %argCount%
set /a count=0
for /l %%x in (1, 1, %argCount%) do (
set /a count=!count!+1
call set "var=%%!count!"
echo var= %!var!
)
But I am facing issues comparing this args with the value. I tried using if as below :
if -> if "!_var!" equ "-logdir" set /a logdir="%%!count!"
But getting error as syntax not correct.

#echo off
setlocal
call :parseArgs %*
if errorlevel 1 exit /b 1
echo env %env%
echo log %log%
echo logdir %logdir%
echo userhome %userhome%
exit /b
:parseArgs
for %%A in (%*) do (
if defined arg (
call set "%%arg%%=%%~1"
set "arg="
) else (
for %%B in (
env
log
logdir
userhome
) do if "%%~A" == "-%%~B" set "arg=%%~B"
if not defined arg (
>&2 echo %%A is an invalid argument.
exit /b 1
)
)
shift
)
exit /b
After the for %%B in ( line is where the valid keywords
are located. If an argument does not define arg, then it
exits the :parseArgs label in which you can check
errorlevel to exit the script.
Does any order with arguments.
E.g.
myscript -env current -log text.log
which would have variable %env% with value current etc.
If you want default values in case i.e. -log is not passed, then
just e.g. set "log=%~n0.log" before the call :parseArgs line.

You claim there can be "many more arguments". The %x syntax can only use the first nine parameters, so with the available %1 to %9 you can only process four pairs, which might be too few. Gladly, the parameters 10... are not lost (although not directly accessible). You can shift the parameter list to the left.
As the parameter pairs "can be passed in different order", it's best to just assign the even parameters (values) to variables named like the odd parameters (variables). I addes some REM's to the code to explain it:
#echo off & setlocal
:loop
if "%~2" == "" goto :done & REM if no other pair of parameters then done
set "%~1=%~2" & REM set variable
shift & REM remove first...
shift & REM ... two params
goto :loop & REM and repeat
:done
REM show parameters:
set -
Note: no syntax check. Parameters are expected to be repeatedly -param and value
To pass parameters with spaces (or other delimiters), quote them like
test.bat -env test1 -logdir "C:\path with spaces\log"

Related

How to substring a certain string using variables as indexes in a batch program

I'm trying to substring a certain string using variables as indexes:
call :subStrFunction 0 1 test
:subStrFunction
set _startchar =%~1
set _endchar =%~2
set _stringInput=%~3
::tried with this
CALL SET subStr=!_stringInput:~%_startchar%,%_endchar%!
::and this (found on http://ss64.com/)
::CALL SET subStr=%%_stringInput:~%_startchar%,%_endchar%%%
::end this
::SET _substring=%_stringInput:~%_startchar %,%_endchar %
echo substring %subStr%
but none of them works >,<
Thx in advance! :D
UPDATE: SOLVED by adding setLocal enableDelayedExpansion
I reworked the batch file to allow for either 1 or both parameters for the sub-string feature.
The turn value will be stored in an environment variable called {str_Return} and will be visible outside of the setlocal environment.
A second environment variable called {bolReturn} will be set to {T} for a successful result and {F} if at least the start position was not supplied or there was an error with the sub-string command.
#Echo Off
call :subStrFunction test 0 1
If "%bolReturn%" EQU "T" (
Echo %str_Return%
) Else (
Echo Command was not successful
)
pause
:subStrFunction
setLocal enableDelayedExpansion
REM String variable needs to be first
set stringInput=%~1
REM If only 1 number is given
If "%~2" EQU "" Goto :l_Missing_Param
If "%~3" EQU "" Goto :l_1_Operand
REM Start and stop parameters given
Set "str_Result=!stringInput:~%~2,%~3!"
If [%ERRORLEVEL%] NEQ [0] Goto :l_Exeuction_Error
Goto :l_Return_Value
:l_1_Operand
REM Start parameter given
Set "str_Result=!stringInput:~%~2!"
If [%ERRORLEVEL%] NEQ [0] Goto :l_Exeuction_Error
Goto :l_Return_Value
:l_Missing_Param
Echo.
Echo You did not provide the correct number of parameters
REM Set Exit value to F for an imcomplete execution
EndLocal & Set bolReturn=F
Goto :EOF
:l_Exeuction_Error
Echo.
Echo An unspecified error has occured!
REM Set Exit value to F for an imcomplete execution
EndLocal & Set bolReturn=F
Goto :EOF
:l_Return_Value
REM Store result value in stable variable
EndLocal & Set "str_Return=%str_Result%"
REM Set Exit value to T for a complete execution
Set bolReturn=T
Goto :EOF
You can either use this as a sub-routine or for a seperate batch file entirely.
p.s. If you copy this code into your own batch file, make very sure that each quote {"} used is an actual quote and not one of the curly quotes or the batch file will fail.

How do you iterate through a subset of the parameters passed to a batch file?

Inside a batch file, how do you iterate through a subset of the command line arguments passed to the batch file?
I can find lots of examples, but none seems to deal with this exact scenario.
Here is a demo example using shift command as suggested by Scott C:
#echo off
set "Count=0"
:NextParameter
if "%~1" == "" goto Done
set /A Count+=1
echo Parameter %Count% is: "%~1"
shift
goto NextParameter
:Done
echo %Count% parameters processed.
set "Count="
The absolute minimum loop would be:
#echo off
:NextParameter
if "%~1" == "" goto :EOF
echo Processing parameter: "%~1"
shift
goto NextParameter
In the loop always first parameter is evaluated for being an empty string. The loop exits if this condition becomes true.
Otherwise it can be done whatever should be done with the current parameter using "%~1" or just %1 or whatever is needed, see help output in a command prompt window on executing there call /? or help call.
Command shift shifts all arguments to left by 1 making it possible to access the next parameter again with %1. Help of command shift can be read with shift /? executed in a command prompt window.
The two examples above fail to process all parameters correct if the batch file is called with 1 or more empty parameters.
For example calling minimum example with Arg1 "argument 2" "" "arg 4" results in the output:
Processing parameter: "Arg1"
Processing parameter: "argument 2"
This can be solved with following batch code:
#echo off
:NextParameter
if "%~1" == "" (
if not [%1] == [""] goto :EOF
)
echo Processing parameter: "%~1"
shift
goto NextParameter
This third batch file called with Arg1 "argument 2" "" "arg 4" outputs correct:
Processing parameter: "Arg1"
Processing parameter: "argument 2"
Processing parameter: ""
Processing parameter: "arg 4"
It is of course also possible to skip empty parameter in list, for example with:
#echo off
:NextParameter
if "%~1" == "" (
if [%1] == [""] (
echo Skipping empty parameter.
shift
goto NextParameter
)
goto :EOF
)
echo Processing parameter: "%~1"
shift
goto NextParameter
This last batch file called with Arg1 "argument 2" "" "arg 4" outputs:
Processing parameter: "Arg1"
Processing parameter: "argument 2"
Skipping empty parameter.
Processing parameter: "arg 4"
But batch files are usually not called with empty parameters.
I think the simplest way is to first load the parameters in an array, and then process array elements in any way you wish:
#echo off
setlocal EnableDelayedExpansion
rem Load parameters in "parV" array and "parC" counter
set parC=0
for %%a in (%*) do (
set /A parC+=1
set parV[!parC!]=%%a
)
rem Show parameters from 3 to N
for /L %%i in (3,1,%parC%) do echo %%i- !parV[%%i]!
If the parameters may contain wild-card characters (* or ?), then the parameters must be loaded in the array via the classical shift loop:
rem Load parameters in parV/parC even if they have wild-cards
set parC=0
:nextPar
if "%~1" equ "" goto endPars
set /A parC+=1
set "parV[!parC!]=%~1"
shift
goto nextPar
:endPars
For a further description on array management in Batch files, see this post.

How to make SHIFT work with %* in batch files

In my batch file on Windows XP, I want to use %* to expand to all parameters except the first.Test file (foo.bat):
#echo off
echo %*
shift
echo %*
Call:
C:\> foo a b c d e f
Actual result:
a b c d e f
a b c d e f
Desired result:
a b c d e f
b c d e f
How can I achieve the desired result? Thanks!!
Wouldn't it be wonderful if CMD.EXE worked that way! Unfortunately there is not a good syntax that will do what you want. The best you can do is parse the command line yourself and build a new argument list.
Something like this can work.
#echo off
setlocal
echo %*
shift
set "args="
:parse
if "%~1" neq "" (
set args=%args% %1
shift
goto :parse
)
if defined args set args=%args:~1%
echo(%args%
But the above has problems if an argument contains special characters like ^, &, >, <, | that were escaped instead of quoted.
Argument handling is one of many weak aspects of Windows batch programming. For just about every solution, there exists an exception that causes problems.
That´s easy:
setlocal ENABLEDELAYEDEXPANSION
set "_args=%*"
set "_args=!_args:*%1 =!"
echo/%_args%
endlocal
Same thing with comments:
:: Enable use of ! operator for variables (! works as % after % has been processed)
setlocal ENABLEDELAYEDEXPANSION
set "_args=%*"
:: Remove %1 from %*
set "_args=!_args:*%1 =!"
:: The %_args% must be used here, before 'endlocal', as it is a local variable
echo/%_args%
endlocal
Example:
lets say %* is "1 2 3 4":
setlocal ENABLEDELAYEDEXPANSION
set "_args=%*" --> _args=1 2 3 4
set "_args=!_args:*%1 =!" --> _args=2 3 4
echo/%_args%
endlocal
Remarks:
Does not work if any argument contains the ! or & char
Any extra spaces in between arguments will NOT be removed
%_args% must be used before endlocal, because it is a local variable
If no arguments entered, %_args% returns * =
Does not shift if only 1 argument entered
Don't think there's a simple way to do so. You could try playing with the following workaround instead:
#ECHO OFF
>tmp ECHO(%*
SET /P t=<tmp
SETLOCAL EnableDelayedExpansion
IF DEFINED t SET "t=!t:%1 =!"
ECHO(!t!
Example:
test.bat 1 2 3=4
Output:
2 3=4
Another easy way of doing this is:
set "_args=%*"
set "_args=%_args:* =%"
echo/%_args%
Remarks:
Does not work if first argument (%1) is 'quoted' or "double quoted"
Does not work if any argument contains the & char
Any extra spaces in between arguments will NOT be removed
I had to do this recently and came up with this:
setlocal EnableDelayedExpansion
rem Number of arguments to skip
set skip=1
for %%a in (%*) do (
if not !position! lss !skip! (
echo Argument: '%%a'
) else (
set /a "position=!position!+1"
)
)
endlocal
It uses loop to skip over N first arguments. Can be used to execute some command per argument or build new argument list:
setlocal EnableDelayedExpansion
rem Number of arguments to skip
set skip=1
for %%a in (%*) do (
if not !position! lss !skip! (
set args=!args! %%a
) else (
set /a "position=!position!+1"
)
)
echo %args%
endlocal
Please note that the code above will add leading space to the new arguments. It can be removed like this:
How to remove trailing and leading whitespace for user-provided input in a batch file?
Yet another obnoxious shortcoming of DOS/Windows batch programming...
Not sure if this is actually better than some of the other answers here but thought I'd share something that seems to be working for me. This solution uses FOR loops rather than goto, and is contained in a reusable batch script.
Separate batch script, "shiftn.bat":
#echo off
setlocal EnableDelayedExpansion
set SHIFTN=%1
FOR %%i IN (%*) DO IF !SHIFTN! GEQ 0 ( set /a SHIFTN=!SHIFTN! - 1 ) ELSE ( set SHIFTEDARGS=!SHIFTEDARGS! %%i )
IF "%SHIFTEDARGS%" NEQ "" echo %SHIFTEDARGS:~1%
How to use shiftn.bat in another batch script; in this example getting all arguments following the first (skipped) arg:
FOR /f "usebackq delims=" %%i IN (`call shiftn.bat 1 %*`) DO set SHIFTEDARGS=%%i
Perhaps someone else can make use of some aspects of this solution (or offer suggestions for improvement).
Resume of all and fix all problems:
set Args=%1
:Parse
shift
set First=%1
if not defined First goto :EndParse
set Args=%Args% %First%
goto :Parse
:EndParse
Unsupport spaces between arguments: 1 2 3 4 will be 1 2 3 4

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 or undefined 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

How can I pass arguments to a batch file?

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:
test.cmd admin P#55w0rd > test-log.txt
Another useful tip is to use %* to mean "all". For example:
echo off
set arg1=%1
set arg2=%2
shift
shift
fake-command /u %arg1% /p %arg2% %*
When you run:
test-command admin password foo bar
The above batch file will run:
fake-command /u admin /p password admin password foo bar
I may have the syntax slightly wrong, but this is the general idea.
Here's how I did it:
#fake-command /u %1 /p %2
Here's what the command looks like:
test.cmd admin P#55w0rd > test-log.txt
The %1 applies to the first parameter the %2 (and here's the tricky part) applies to the second. You can have up to 9 parameters passed in this way.
If you want to intelligently handle missing parameters you can do something like:
IF %1.==. GOTO No1
IF %2.==. GOTO No2
... do stuff...
GOTO End1
:No1
ECHO No param 1
GOTO End1
:No2
ECHO No param 2
GOTO End1
:End1
Accessing batch parameters can be simple with %1, %2, ... %9 or also %*,
but only if the content is simple.
There is no simple way for complex contents like "&"^&, as it's not possible to access %1 without producing an error.
set var=%1
set "var=%1"
set var=%~1
set "var=%~1"
The lines expand to
set var="&"&
set "var="&"&"
set var="&"&
set "var="&"&"
And each line fails, as one of the & is outside of the quotes.
It can be solved with reading from a temporary file a remarked version of the parameter.
#echo off
SETLOCAL DisableDelayedExpansion
SETLOCAL
for %%a in (1) do (
set "prompt="
echo on
for %%b in (1) do rem * #%1#
#echo off
) > param.txt
ENDLOCAL
for /F "delims=" %%L in (param.txt) do (
set "param1=%%L"
)
SETLOCAL EnableDelayedExpansion
set "param1=!param1:*#=!"
set "param1=!param1:~0,-2!"
echo %%1 is '!param1!'
The trick is to enable echo on and expand the %1 after a rem statement (works also with %2 .. %*).
So even "&"& could be echoed without producing an error, as it is remarked.
But to be able to redirect the output of the echo on, you need the two for-loops.
The extra characters * # are used to be safe against contents like /? (would show the help for REM).
Or a caret ^ at the line end could work as a multiline character, even in after a rem.
Then reading the rem parameter output from the file, but carefully.
The FOR /F should work with delayed expansion off, else contents with "!" would be destroyed.
After removing the extra characters in param1, you got it.
And to use param1 in a safe way, enable the delayed expansion.
Yep, and just don't forget to use variables like %%1 when using if and for and the gang.
If you forget the double %, then you will be substituting in (possibly null) command line arguments and you will receive some pretty confusing error messages.
A friend was asking me about this subject recently, so I thought I'd post how I handle command-line arguments in batch files.
This technique has a bit of overhead as you'll see, but it makes my batch files very easy to understand and quick to implement. As well as supporting the following structures:
>template.bat [-f] [--flag] [--namedvalue value] arg1 [arg2][arg3][...]
The jist of it is having the :init, :parse, and :main functions.
Example usage
>template.bat /?
test v1.23
This is a sample batch file template,
providing command-line arguments and flags.
USAGE:
test.bat [flags] "required argument" "optional argument"
/?, --help shows this help
/v, --version shows the version
/e, --verbose shows detailed output
-f, --flag value specifies a named parameter value
>template.bat <- throws missing argument error
(same as /?, plus..)
**** ****
**** MISSING "REQUIRED ARGUMENT" ****
**** ****
>template.bat -v
1.23
>template.bat --version
test v1.23
This is a sample batch file template,
providing command-line arguments and flags.
>template.bat -e arg1
**** DEBUG IS ON
UnNamedArgument: "arg1"
UnNamedOptionalArg: not provided
NamedFlag: not provided
>template.bat --flag "my flag" arg1 arg2
UnNamedArgument: "arg1"
UnNamedOptionalArg: "arg2"
NamedFlag: "my flag"
>template.bat --verbose "argument #1" --flag "my flag" second
**** DEBUG IS ON
UnNamedArgument: "argument #1"
UnNamedOptionalArg: "second"
NamedFlag: "my flag"
template.bat
#::!/dos/rocks
#echo off
goto :init
:header
echo %__NAME% v%__VERSION%
echo This is a sample batch file template,
echo providing command-line arguments and flags.
echo.
goto :eof
:usage
echo USAGE:
echo %__BAT_NAME% [flags] "required argument" "optional argument"
echo.
echo. /?, --help shows this help
echo. /v, --version shows the version
echo. /e, --verbose shows detailed output
echo. -f, --flag value specifies a named parameter value
goto :eof
:version
if "%~1"=="full" call :header & goto :eof
echo %__VERSION%
goto :eof
:missing_argument
call :header
call :usage
echo.
echo **** ****
echo **** MISSING "REQUIRED ARGUMENT" ****
echo **** ****
echo.
goto :eof
:init
set "__NAME=%~n0"
set "__VERSION=1.23"
set "__YEAR=2017"
set "__BAT_FILE=%~0"
set "__BAT_PATH=%~dp0"
set "__BAT_NAME=%~nx0"
set "OptHelp="
set "OptVersion="
set "OptVerbose="
set "UnNamedArgument="
set "UnNamedOptionalArg="
set "NamedFlag="
:parse
if "%~1"=="" goto :validate
if /i "%~1"=="/?" call :header & call :usage "%~2" & goto :end
if /i "%~1"=="-?" call :header & call :usage "%~2" & goto :end
if /i "%~1"=="--help" call :header & call :usage "%~2" & goto :end
if /i "%~1"=="/v" call :version & goto :end
if /i "%~1"=="-v" call :version & goto :end
if /i "%~1"=="--version" call :version full & goto :end
if /i "%~1"=="/e" set "OptVerbose=yes" & shift & goto :parse
if /i "%~1"=="-e" set "OptVerbose=yes" & shift & goto :parse
if /i "%~1"=="--verbose" set "OptVerbose=yes" & shift & goto :parse
if /i "%~1"=="--flag" set "NamedFlag=%~2" & shift & shift & goto :parse
if /i "%~1"=="-f" set "NamedFlag=%~2" & shift & shift & goto :parse
if not defined UnNamedArgument set "UnNamedArgument=%~1" & shift & goto :parse
if not defined UnNamedOptionalArg set "UnNamedOptionalArg=%~1" & shift & goto :parse
shift
goto :parse
:validate
if not defined UnNamedArgument call :missing_argument & goto :end
:main
if defined OptVerbose (
echo **** DEBUG IS ON
)
echo UnNamedArgument: "%UnNamedArgument%"
if defined UnNamedOptionalArg echo UnNamedOptionalArg: "%UnNamedOptionalArg%"
if not defined UnNamedOptionalArg echo UnNamedOptionalArg: not provided
if defined NamedFlag echo NamedFlag: "%NamedFlag%"
if not defined NamedFlag echo NamedFlag: not provided
:end
call :cleanup
exit /B
:cleanup
REM The cleanup function is only really necessary if you
REM are _not_ using SETLOCAL.
set "__NAME="
set "__VERSION="
set "__YEAR="
set "__BAT_FILE="
set "__BAT_PATH="
set "__BAT_NAME="
set "OptHelp="
set "OptVersion="
set "OptVerbose="
set "UnNamedArgument="
set "UnNamedArgument2="
set "NamedFlag="
goto :eof
There is no need to complicate it. It is simply command %1 %2 parameters, for example,
#echo off
xcopy %1 %2 /D /E /C /Q /H /R /K /Y /Z
echo copied %1 to %2
pause
The "pause" displays what the batch file has done and waits for you to hit the ANY key. Save that as xx.bat in the Windows folder.
To use it, type, for example:
xx c:\f\30\*.* f:\sites\30
This batch file takes care of all the necessary parameters, like copying only files, that are newer, etc. I have used it since before Windows. If you like seeing the names of the files, as they are being copied, leave out the Q parameter.
In batch file
set argument1=%1
set argument2=%2
echo %argument1%
echo %argument2%
%1 and %2 return the first and second argument values respectively.
And in command line, pass the argument
Directory> batchFileName admin P#55w0rd
Output will be
admin
P#55w0rd
#ECHO OFF
:Loop
IF "%1"=="" GOTO Continue
SHIFT
GOTO Loop
:Continue
Note: IF "%1"=="" will cause problems if %1 is enclosed in quotes itself.
In that case, use IF [%1]==[] or, in NT 4 (SP6) and later only, IF "%~1"=="" instead.
Everyone has answered with really complex responses, however it is actually really simple. %1 %2 %3 and so on are the arguements parsed to the file. %1 is arguement 1, %2 is arguement 2 and so on.
So, if I have a bat script containing this:
#echo off
echo %1
and when I run the batch script, I type in this:
C:> script.bat Hello
The script will simply output this:
Hello
This can be very useful for certain variables in a script, such as a name and age. So, if I have a script like this:
#echo off
echo Your name is: %1
echo Your age is: %2
When I type in this:
C:> script.bat Oliver 1000
I get the output of this:
Your name is: Oliver
Your age is: 1000
Let's keep this simple.
Here is the .cmd file.
#echo off
rem this file is named echo_3params.cmd
echo %1
echo %2
echo %3
set v1=%1
set v2=%2
set v3=%3
echo v1 equals %v1%
echo v2 equals %v2%
echo v3 equals %v3%
Here are 3 calls from the command line.
C:\Users\joeco>echo_3params 1abc 2 def 3 ghi
1abc
2
def
v1 equals 1abc
v2 equals 2
v3 equals def
C:\Users\joeco>echo_3params 1abc "2 def" "3 ghi"
1abc
"2 def"
"3 ghi"
v1 equals 1abc
v2 equals "2 def"
v3 equals "3 ghi"
C:\Users\joeco>echo_3params 1abc '2 def' "3 ghi"
1abc
'2
def'
v1 equals 1abc
v2 equals '2
v3 equals def'
C:\Users\joeco>
FOR %%A IN (%*) DO (
REM Now your batch file handles %%A instead of %1
REM No need to use SHIFT anymore.
ECHO %%A
)
This loops over the batch parameters (%*) either they are quoted or not, then echos each parameter.
I wrote a simple read_params script that can be called as a function (or external .bat) and will put all variables into the current environment. It won't modify the original parameters because the function is being called with a copy of the original parameters.
For example, given the following command:
myscript.bat some -random=43 extra -greeting="hello world" fluff
myscript.bat would be able to use the variables after calling the function:
call :read_params %*
echo %random%
echo %greeting%
Here's the function:
:read_params
if not %1/==/ (
if not "%__var%"=="" (
if not "%__var:~0,1%"=="-" (
endlocal
goto read_params
)
endlocal & set %__var:~1%=%~1
) else (
setlocal & set __var=%~1
)
shift
goto read_params
)
exit /B
Limitations
Cannot load arguments with no value such as -force. You could use -force=true but I can't think of a way to allow blank values without knowing a list of parameters ahead of time that won't have a value.
Changelog
2/18/2016
No longer requires delayed expansion
Now works with other command line arguments by looking for - before parameters.
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 <command> [--foo [<fooval>]] [--bar <barval>] [--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 ^<command^> [--foo [^<fooval^>]] [--bar ^<barval^>] [--baz]
EXIT /B 1
Use SETLOCAL so that the variables don't escape into the calling environment.
Don't forget to initialize the variables SET FOO=, etc. in case someone defined them in the calling environment.
Use %~1 to remove quotes.
Use IF "%ARG%" == "" and not IF [%ARG%] == [] because [ and ] don't play will at all with values ending in a space.
Even if you 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.
You don't want to use a parameter in place of another parameter's optional value, so you have to check IF NOT "%ARG:~0,2%" == "--".
Be careful only to SHIFT when you use one of the parameters.
The duplicate code 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.
Note that ECHO Missing bar value. 1>&2 sends the error message to stderr.
Want a blank line in a Windows batch file? You gotta use ECHO: or one of the variations.
To refer to a set variable in command line you would need to use %a% so for example:
set a=100
echo %a%
rem output = 100
Note: This works for Windows 7 pro.
For to use looping get all arguments and in pure batch:
Obs: For using without: ?*&|<>
#echo off && setlocal EnableDelayedExpansion
for %%Z in (%*)do set "_arg_=%%Z" && set/a "_cnt+=1+0" && (
call set "_arg_[!_cnt!]=!_arg_!" && for /l %%l in (!_cnt! 1 !_cnt!
)do echo/ The argument n:%%l is: !_arg_[%%l]!
)
goto :eof
Your code is ready to do something with the argument number where it needs, like...
#echo off && setlocal EnableDelayedExpansion
for %%Z in (%*)do set "_arg_=%%Z" && set/a "_cnt+=1+0" && call set "_arg_[!_cnt!]=!_arg_!"
fake-command /u !_arg_[1]! /p !_arg_[2]! > test-log.txt
Simple solution(even though question is old)
Test1.bat
echo off
echo "Batch started"
set arg1=%1
echo "arg1 is %arg1%"
echo on
pause
CallTest1.bat
call "C:\Temp\Test1.bat" pass123
output
YourLocalPath>call "C:\Temp\test.bat" pass123
YourLocalPath>echo off
"Batch started"
"arg1 is pass123"
YourLocalPath>pause
Press any key to continue . . .
Where YourLocalPath is current directory path.
To keep things simple store the command param in variable and use variable for comparison.
Its not just simple to write but its simple to maintain as well so if later some other person or you read your script after long period of time, it will be easy to understand and maintain.
To write code inline : see other answers.
Make a new batch file (example: openclass.bat) and write this line in the file:
java %~n1
Then place the batch file in, let's say, the system32 folder, go to your Java class file, right click, Properties, Open with..., then find your batch file, select it and that's that...
It works for me.
PS: I can't find a way to close the cmd window when I close the Java class. For now...
Paired arguments
If you prefer passing the arguments in a key-value pair you can use something like this:
#echo off
setlocal enableDelayedExpansion
::::: asigning arguments as a key-value pairs:::::::::::::
set counter=0
for %%# in (%*) do (
set /a counter=counter+1
set /a even=counter%%2
if !even! == 0 (
echo setting !prev! to %%#
set "!prev!=%%~#"
)
set "prev=%%~#"
)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: showing the assignments
echo %one% %two% %three% %four% %five%
endlocal
And an example :
c:>argumentsDemo.bat one 1 "two" 2 three 3 four 4 "five" 5
1 2 3 4 5
Predefined variables
You can also set some environment variables in advance. It can be done by setting them in the console or setting them from my computer:
#echo off
if defined variable1 (
echo %variable1%
)
if defined variable2 (
echo %variable2%
)
and calling it like:
c:\>set variable1=1
c:\>set variable2=2
c:\>argumentsTest.bat
1
2
File with listed values
You can also point to a file where the needed values are preset.
If this is the script:
#echo off
setlocal
::::::::::
set "VALUES_FILE=E:\scripts\values.txt"
:::::::::::
for /f "usebackq eol=: tokens=* delims=" %%# in ("%VALUES_FILE%") do set "%%#"
echo %key1% %key2% %some_other_key%
endlocal
and values file is this:
:::: use EOL=: in the FOR loop to use it as a comment
key1=value1
key2=value2
:::: do not left spaces arround the =
:::: or at the begining of the line
some_other_key=something else
and_one_more=more
the output of calling it will be:
value1 value2 something else
Of course you can combine all approaches. Check also arguments syntax , shift
If you're worried about security/password theft (that led you to design this solution that takes login credentials at execution instead of static hard coding without the need for a database), then you could store the api or half the code of password decryption or decryption key in the program file, so at run time, user would type username/password in console to be hashed/decrypted before passed to program code for execution via set /p, if you're looking at user entering credentials at run time.
If you're running a script to run your program with various user/password, then command line args will suit you.
If you're making a test file to see the output/effects of different logins, then you could store all the logins in an encrypted file, to be passed as arg to test.cmd, unless you wanna sit at command line & type all the logins until finished.
The number of args that can be supplied is limited to total characters on command line. To overcome this limitation, the previous paragraph trick is a workaround without risking exposure of user passwords.

Resources