34

I would like to know how to call more than 9 argument within a batch script when calling a label. For example, the following shows that I have 12 arguments assigned along with attempting to echo all of them.

CALL:LABEL "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "ten" "eleven" "twelve"
PAUSE
GOTO:EOF


:LABEL
echo %1
echo %2
echo %3
echo %4
echo %5
echo %6
echo %7
echo %8
echo %9
echo %10
echo %11
echo %12

The output for %10 %11 and %12 ends up being one0 one1 one2. I've tried using curly brackets, brackets, quotations, single quotes around the numbers without any luck.

Anthony Miller
  • 15,101
  • 28
  • 69
  • 98
  • 2
    I would like to add that `SHIFT` allows for a `/N` switch to be used in conjunction with it it to select which argument to start from. For example, if you've used SHIFT to access a 10th argument, in order to access argument 0 again (your absolute path to the currently running batch script), you can use `SHIFT /N 0` which resets you back to your original 0-9 arguments. – Anthony Miller Nov 30 '11 at 16:24
  • Possible duplicate of [How to pass more than 9 parameters to batch file](https://stackoverflow.com/questions/21694861/how-to-pass-more-than-9-parameters-to-batch-file) – Badasahog Nov 09 '18 at 15:11
  • [This answer within this other solution](https://stackoverflow.com/a/38119090/1779936) is excellent and it allows for an arbitrary number of parameters, which are then saved and can be used later. – Gigamosh57 Aug 15 '23 at 16:03

7 Answers7

36

Use the shift command if you want to work with more than 9 parameters.
(actually more than 10 parameters if you count the %0 parameter)

You can [...] use the shift command to create a batch file that can accept more than 10 batch parameters. If you specify more than 10 parameters on the command line, those that appear after the tenth (%9) will be shifted one at a time into %9.

You can either use a loop, store the variables before shifting, or do it quick like this:

@echo off
CALL:LABEL "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "ten" "eleven" "twelve"
PAUSE
GOTO:EOF

:LABEL
:: print arguments 1-9
echo %1
echo %2
echo %3
echo %4
echo %5
echo %6
echo %7
echo %8
echo %9

:: print arguments 10-11
shift
shift 
echo %8
echo %9

:: print argument 13
shift
echo %9

You can replace the shift commands with a loop in case you have many arguments. The following for loop executes shift nine times, so that %1 will be the tenth argument.

@for /L %%i in (0,1,8) do shift
kapex
  • 28,903
  • 6
  • 107
  • 121
11

Just throwing my hat in the ring if it helps anyone

Set a=%1 & Set b=%2 & Set c=%3 & Set d=%4 & Set e=%5 & Set f=%6 & Set g=%7 & Set h=%8 & Set i=%9
Shift & Shift & Shift & Shift & Shift & Shift & Shift & Shift & Shift
Set j=%1 & Set k=%2 & Set l=%3 & Set m=%4 & Set n=%5 & Set o=%6 & Set p=%7 & Set q=%8 & Set r=%9
Shift & Shift & Shift & Shift & Shift & Shift & Shift & Shift & Shift
Set s=%1 & Set t=%2 & Set u=%3 & Set v=%4 & Set w=%5 & Set x=%6 & Set y=%7 & Set z=%8

I just put this at the top of the .bat or subroutine that will use >9 args, then you can use %a% through %z% instead of %1 to the non-existent %26.

It's pretty ugly, originally I had it all one one line à la

Set a=%1 & Shift & Set b=%1 & Shift &...

That way it's only on one line and gets hidden behind the edge of the editor pretty swiftly, but apparently Shift won't take effect until the next true line; all the variables were set to the first parameter.

If you're wondering why do this instead of the loops, unless someone shows me you can create a sort of map or array, I needed to use the variables in a one-line command, not echo (or do whatever) with them one at a time:

::example; concatenate a bunch of files
Set output=%1
Shift
<insert above behemoth>
type %a% %b% %c% %d% %e% %f% 2>NUL > %output%

Damn this was so much easier in bash

cat ${@:2} > "$1"
Hashbrown
  • 12,091
  • 8
  • 72
  • 95
  • The Set a=%1 ...Shift method worked perfectly for me with a batch file with 18 parameters in a single command line to be used together. – Polymath Jan 13 '23 at 16:24
  • How were they joined? `&`s or something I didn't think of? – Hashbrown Jan 14 '23 at 02:44
  • 2
    The only fine-tuning required is removing the space between parameters and ampersands. Like Set a=%1& Set b=%2& Set c=%3& ... Otherwise an unwanted space is appended to the values when substituted. – Polymath Jan 14 '23 at 14:37
8

This is another way to use the shift command.

Note in this case you can use a variable number of parameters.

@ECHO OFF
CALL:LABEL "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "ten" "eleven" "twelve"
PAUSE
GOTO:EOF

:LABEL
echo %1
shift
if not [%1]==[] GOTO LABEL
kkk
  • 818
  • 8
  • 11
8

Assuming we're using a recent-ish version of CMD here, I'm pretty shocked to find no one has posted the following, which allows an arbitrary number of arguments to be processed easily without ever using the clunky shift command:

rem test.bat
call :subr %*
exit /b

:subr
for %%A in (%*) do (
    echo %%A
)
exit /b

You can also do this same technique right in "main" as well.

This way, you don't eat up your arguments as you process them, and there is no need for shift, meaning you can consistently loop through the argument-list more than once if you have complicated calling options and it happens to make your script's logic simpler.

Obviously, if do loop through more than once, it increases computational complexity in exchange for legibility, but neither Bash nor CMD were really built for great speed (as far as I've ever heard) so there's little point in trying to optimize by doing setup all-in-one-go assuming n is any less than 100 or so.

Some sample output:

C:\tmp>test.bat one two three four five six seven eight nine ten eleven
one
two
three
four
five
six
seven
eight
nine
ten
eleven

edit - On the off chance anyone is processing arguments against another list and part of the work is nested, it's important that an intermediary CALL be used to allow the current argument being processed to be transferred into the inner loop; simply doing set intermediary=%%OUTER appears to simply set intermediary to a an empty string, so it's next simplest to do this:

setlocal enabledelayedexpansion
rem ^ in my experience, it's always a good idea to set this if for-loops are involved
for /f %%L in (file.txt) do (
    call :inner %%L
)
exit /b

:inner
for %%A in (%*) do (
    if %%A EQU %~1 call dosomething.bat %~1        
)
exit /b

edit 2 - Also, if for whatever reason you want to add the shift approach into the mix here – perhaps by trying to pass all arguments other than the 1st to a subroutine by using a shift and then using call :subroutine %* – note that it won't work because %* actually gives you all of the original arguments in order, ignorant of any shifting you have done.
It's a shame because there's no native syntax (that I know of) that can group all arguments after a certain one, as one might expect say %3* to do.

3

You cannot have more than 10 (0 through 9) accessible arguments (%0 being the batchfile itself) in a batch file. However, using the shift command will allow you to "left-shift" your arguments, and access those arguments beyond the 9th one. If you do it three times, you should end up with %7, %8 and %9 containing "ten", "eleven" and "twelve".

Laf
  • 7,965
  • 4
  • 37
  • 52
0

I know this old but I figured I'd update for others google searching.

For anyone that is curious, I created a nice dynamic and compact method of doing this, so you can have a variable amount of parameters.

SETLOCAL ENABLEDELAYEDEXPANSION
:ARG
set /A Count+=1
echo !Count!
if "%~1"=="" (
    GOTO ENDARGS
) else (
    <Do Something, call variables with !VarName! instead of %VarName%>
)
shift
GOTO ARG
:ENDARGS
ENDLOCAL

kkk's answer can work as well

Please let me know if anyone has any improvements. I attempted using the following also accepted method. But for people using this method and trying to do something as insane as I am like having more than 27 parameters, this doesn't work. It stops after 27. Or at least that's what I experienced, let me know if you've experienced otherwise.

for %%a in (%*) do (
    <Do Something>
)
Manoch
  • 1
0

Hashbrown had a perfect simple answer to shift 10..n on SETting variables, Polymath had a perfect comment how to avoid trailing whitespaces(& trick).

This is my answer to set 1..18 args, avoid whitespaces and also drop "my param value X" quotes from the input parameters(~ trick).

@rem must shift 10..n input params, avoid whitespaces by using "~1& .."
@set p1=%~1& set p2=%~2& set p3=%~3& set p4=%~4& set p5=%~5& set p6=%~6& set p7=%~7& set p8=%~8& set p9=%~9
@Shift & Shift & Shift & Shift & Shift & Shift & Shift & Shift & Shift
@set p10=%~1& set p11=%~2& set p12=%~3& set p13=%~4& set p14=%~5& set p15=%~6& set p16=%~7& set p17=%~8& set p18=%~9
Whome
  • 10,181
  • 6
  • 53
  • 65