44

I have a batch-script with multiple arguments. I am reading the total count of them and then run a for loop like this:

@echo off
setlocal enabledelayedexpansion

set argCount=0
for %%x in (%*) do set /A argCount+=1
echo Number of processed arguments: %argCount%

set /a counter=0
for /l %%x in (1, 1, %argCount%) do (
set /a counter=!counter!+1 )

What I want to do now, is to use my running variable (x or counter) to access the input arguments. I am thinking aobut something like this:

REM Access to %1 
echo %(!counter!)

In an ideal world this line should print out my first command line argument but obviously it doesn't. I know I am doing something wrong with the % operator, but is there anyway I could access my arguments like this?

//edit: Just to make things clear - the problem is that %(!counter!) provides me with the value of the variable counter. Meaning for counter=2 it gives me 2 and not the content of %2.

Toby
  • 3,815
  • 14
  • 51
  • 67
  • if the arguments are more than 9 you can't access all of them without `shift` – npocmaka Nov 07 '13 at 12:29
  • This is another issue I might encounter, but let's just assume that I will have less than 10 arguments – Toby Nov 07 '13 at 12:30
  • 4
    Also, `for %%x in (%*) do ...` will not give the desired result if any parameter contains `*` or `?` character. I always use a GOTO loop with SHIFT if I want to load the parameters into an array of variables. – dbenham Nov 07 '13 at 16:08
  • If one of the arguments contains a wildcard character, e.g. "file*.txt" then it is not processed. Any idea how to fix? – David Hyde Mar 01 '23 at 10:09

6 Answers6

73
@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]!"

For example:

C:> test One "This is | the & second one" Third
Number of processed arguments: 3
1- "One"
2- "This is | the & second one"
3- "Third"

Another one:

C:> test One Two Three Four Five Six Seven Eight Nine Ten Eleven Twelve etc...
Number of processed arguments: 13
1- "One"
2- "Two"
3- "Three"
4- "Four"
5- "Five"
6- "Six"
7- "Seven"
8- "Eight"
9- "Nine"
10- "Ten"
11- "Eleven"
12- "Twelve"
13- "etc..."
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • 1
    Tthis one is working as is, for me, unlike current solution from @npocmaka (windows 10 familly) – user1767316 Oct 28 '18 at 15:38
  • 1
    A little more context on how the whole thing works would be nice, but the solutions does what it says on the thin, I give you that. :-) – M463 Mar 05 '20 at 15:47
  • This has trouble when the argument has some format, e.g. this link: `https://www.tagesschau.de/investigativ/ndr-wdr/spaeh-software-pegasus-projekt-101.html`. I can't name the exact problem, but it doesn't even count this argument. It probably also has problems if one of the argument contains `*`. – Cadoiz Jul 22 '21 at 16:28
  • Be aware that this needs the delayed expansion (`setlocal enableDelayedExpansion`), which my [preferred answer](https://stackoverflow.com/a/39776524/4575793) doesn't. – Cadoiz Aug 02 '21 at 12:23
  • This answer splits on semicolons. Calling with "One;Two" will output two lines "One" and "Two". – Hypershadsy Apr 08 '23 at 09:23
  • @Hypershadsy: Not true. If you call it with `"One;Two"` (enclosed in quotes) it output just one line. If you don't enclose parameters in quotes, then the usual Batch rules apply: parameters are split at semicolon, comma or equal-sign (besides spaces). For example: `test One;Two,Three=Four` – Aacini Apr 10 '23 at 15:32
35
:loop
@echo %1
shift
if not "%~1"=="" goto loop
Jay Taylor
  • 13,185
  • 11
  • 60
  • 85
  • 5
    Where are the better answers? I like this one because it is super succinct, minimal, and straightforward. – Jay Taylor Sep 30 '16 at 17:12
  • 4
    What I think @jeb is trying to say is that you should provide an explanation for your answer. I think it's great, but with details on what each command does, and maybe a usage example, you'll get more upvotes :) – Christian Rondeau Oct 03 '16 at 22:59
  • 1
    This answer works when the arguments contain special characters like `*` but iterates one time too many when there are no arguments. – Arnaud Feb 22 '20 at 21:25
  • Very helpful information @Arnaud, thank you for explaining the issue and shedding light on this! – Jay Taylor Mar 11 '20 at 15:43
  • that's my choice, for sure! – Caverna Jan 08 '21 at 13:42
  • Found this to be by far the most reliable solution. It also handles `parameter_iteration_3.bat https://www.tagesschau.de/investigativ/ndr-wdr/spaeh-software-pegasus-smartphone-101.html?utm_source=pocket-newtab-global-de-DE ** * te*st` as the only solution and also correctly deals with `""` – Cadoiz Jul 22 '21 at 16:31
  • This breaks when an empty argument `""` is in the mix, skipping anything after. Also, I can't get this version to preserve equals signs :( – Ben Philipp Jul 05 '22 at 14:35
14

here's one way to access the second (e.g.) argument (this can be put in a for /l loop, see below.):

@echo off
setlocal enableDelayedExpansion
set /a counter=2
call echo %%!counter!
endlocal

so:

setlocal enableDelayedExpansion
set /a counter=0
for /l %%x in (1, 1, %argCount%) do (
 set /a counter=!counter!+1
 call echo %%!counter! 
)
endlocal
Cadoiz
  • 1,446
  • 21
  • 31
npocmaka
  • 55,367
  • 18
  • 148
  • 187
  • Ok I need to ask, even if it may obvious and I am just having a blackout: Is there any way how I can get that value into a variable now? Now that I have read the Input paramaeters I want to compare them with some strings. And I am not quite sure how I can access that string now...? – Toby Nov 07 '13 at 13:33
  • with call `set "_var=%%!counter!"`.you need a temp variable because [if cannot be called](http://stackoverflow.com/questions/19445153/why-i-cant-call-if-and-for-neither-in-batch-nor-in-the-cmd) – npocmaka Nov 07 '13 at 13:37
  • and then you can compare with if -> `if "!_var!" equ "something" echo this is something` – npocmaka Nov 07 '13 at 13:41
  • Are you sure that I have to put the `"` around the whole `set` call? – Toby Nov 07 '13 at 13:45
  • it is `a safe` strategy. this allows you to include special characters in the value like `|&><....` and will ensure you that there is no extra space at the end (which in some cases could break your logic) – npocmaka Nov 07 '13 at 13:46
  • The problem is, when I assign it to `_var` , `_var` also just contains `%1` etc (using `echo !_var!`) - When I use `call echo !_var!` I get the contents again - the problem is when I use `_var` in my `if` call (liek you suggest) it unfortunately doesn't work – Toby Nov 07 '13 at 13:55
  • `call set` ...the call accidentally was left outside the grey bckg. – npocmaka Nov 07 '13 at 13:57
  • `call set "_var=%%!counter!"` – npocmaka Nov 07 '13 at 13:58
  • Be aware that this needs the delayed expansion (`setlocal enableDelayedExpansion`), which my [preferred answer](https://stackoverflow.com/a/39776524/4575793) doesn't. You could also add an `@echo off` in front. – Cadoiz Aug 02 '21 at 12:23
  • @Cadoiz - mind that using labels and GOTO for loops can be low performing approach. – npocmaka Aug 02 '21 at 12:35
10

If to keep the code short rather than wise, then

for %%x in (%*) do (
   echo Hey %%~x 
)
Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93
2
@ECHO OFF
SETLOCAL
SET nparms=0
FOR /l %%i IN (1,1,20) DO (
 SET myparm=%%i
 CALL :setparm %*
 IF DEFINED myparm SET nparms=%%i&CALL ECHO Parameter %%i=%%myparm%%
)
ECHO there were %nparms% parameters in %*
GOTO :EOF

:setparm
IF %myparm%==1 SET myparm=%1&GOTO :EOF
shift&SET /a myparm -=1&GOTO setparm
GOTO :eof

This should show how to extract random parameters by position.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • Are you counting the number of command-line arguments? – johny why Nov 21 '21 at 20:02
  • @johnywhy No, that was done in the original post. This demonstration is of how to access any arbitrary parameter by position since for instance %13 to get the 13th parameter will actually tag "3" onto the end of the first parameter (%1) as only a single digit is allowed in this position. The demo shows the first 20 parameters as set by the `for/l` loop. The number in `nparms` is actually the last-detected parameter number that was defined. Change the loop to `for %%i in (6,3,25,11,9) do` and it will report the last parameter number defined of the set `(6,3,25,11,9)` as `nparms` – Magoo Nov 25 '21 at 23:19
2

For simple iteration can't we just check for additional arguments with "shift /1" at the end of the code and loop back? This will handle more than 10 arguments, upper limit not tested.

:loop

:: Your code using %1
echo %1

:: Check for further batch arguments.     
shift /1
IF [%1]==[] (
goto end
) ELSE (
goto loop
)

:end
pause
Gavin
  • 477
  • 5
  • 16