How do I detect the number of parameters to a batch file and loop through them?

Is there an easy way to detect the number of parameters passed as arguments to a batch file, and then use for /L to loop through them?


Solution 1:

How do I detect the number of parameters to a batch file and loop through them?

%* in a batch script refers to all the arguments (e.g. %1 %2 %3 %4 %5 ...%255)

You can use %* to retrieve all of the command line arguments to a batch file.

To count the arguments and loop with for /L see the StackOverflow answer Batch-Script - Iterate through arguments by aacini:

@echo off
setlocal enabledelayedexpansion

set argCount=0
for %%x in (%*) do (
   set /A argCount+=1
   set "argVec[!argCount!]=%%~x"
)

echo Number of processed arguments: %argCount%

for /L %%i in (1,1,%argCount%) do echo %%i- "!argVec[%%i]!"

Further Reading

  • An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
  • for - Conditionally perform a command several times.
  • parameters - A command line argument (or parameter) is any value passed into a batch script:

Solution 2:

In general @DavidPostill has the correct answer. It will not see /? switches though (and possibly a few others). If you would like to see those, then you may use: for %%x in ("%*") do ( instead of for %%x in (%*) do (. The problem with that is that this version won't see anything in quotes. If you'd like a version which can do both then here is a decidedly less simple answer:

@set @junk=1 /*
@ECHO OFF
:: Do not changes the above two lines. They are required in order to make the 
:: JScript below work.

:: In order to get the parameter count from WSH we will call this script 
:: three times in three different ways. The first time, it'll run the code in this
:: section just as any normal BATCH script would. At the end of this section, it'll 
:: call cscript.exe in order to run the JScript portion below.

:: The final call will be the same call as was originally requested but with the 
:: difference of the first parameter being the word redux (if that is a possible 
:: valid value for your script then you'll want to change it here and in the 
:: JScript below as well).
IF "%1" == "redux" @GOTO :CLOSINGTIME

:: The next step passes this script to get the WSH command line executable for 
:: further processing.
cscript //nologo //E:jscript %~f0 %*

:: Exit the initial call to this script.
GOTO:EOF */

// We are now in the second iteration of the call. Here we are using JScript 
// instead of batch because WSH is much better at counting it's parameters.

var args=WScript.Arguments, 
    sh=WScript.CreateObject("WScript.Shell"),
    cmd="%comspec% /k " + WScript.ScriptFullName + ' redux ' + args.length;

for(var i=0, j=args.length; i<j; i++)
    cmd+=' "' + args(i) + '"';

// sh.Popup("The generated command line is:\n  "+cmd);

var exec=sh.Exec(cmd);
while(!exec.StdOut.AtEndOfStream)
  WScript.Echo(exec.StdOut.ReadLine());

// Leave the script now. Remember that the entire script needs to be parsable by
// WSH so be sure that anything after this line is in the comment below.
WScript.Quit(0);

/* This line is here to hide the rest of the file from WSH.
========================================================================

:CLOSINGTIME

:: Now we've called this script 3 times (once manually and now twice more just
:: to get back here knowing the correct argument count. We've added that value
:: to the command line so lets remove that cruft before we call this done.

:: Remove the static, redux, parameter
SHIFT

:: Save the argument count.
SET ARGC=%1

:: Remove ARGC parameter
SHIFT

:: Now you are ready to use your batch code. The variable %ARGC% contains the
:: argument count of the original call.


:: ******************************
:: ** START OF YOUR BATCH CODE **
:: ******************************

ECHO Fancy JScript count: %ARGC%
ECHO.

:: ****************************
:: ** END OF YOUR BATCH CODE **
:: ****************************

:: This is needed in order to let the JScript portion know that output has ended.
EXIT

:: ========================================================================
:: This line will hide everything in your second BATCH portion from WSH. */

Unfortunately, this isn't a perfect answer either because of the way that we had to execute the file from within WSH, StdErr and StdOut are both broken for the final script. You can fix the StdErr in certain situations by using 2&>1 at the end of the second batch call: var exec=sh.Exec(cmd+" 2&>1"); StdIn will need to be handled as a special case for each script though.