3

I am trying to create some sort of handler for arguments passed into my script. The idea is to handle "pairs" of arguments together. So, that is to say 1 and 2, 3 and 4, 5 and 6, and so on... (NOT 2 and 3, 4 and 5, 6 and 7, and so on...)

I think batch is very cool, but I am very new to batch. I am lost as how to do it. So far I have managed to successfully put the arguments into an array with the following script:

SETLOCAL EnableDelayedExpansion
set /a count+=1
set "params[%count%]=%~1"
shift
if defined params[%count%] (
    goto :repeat
) else (
    set /a count-=1
)

Now I just need to handle each of the elements in pairs. I don't know how to do this at all. I know how to handle the elements individually with for /F "tokens=2 delims==" %%s in ('set params[') do, but I don't know how to do pairs

on the side can someone explain what the delayed expansion thing is supposed to do?

just for clarity, by "handle" I mean to manipulate it and pass it on as an argument onto another script. this must be done in pairs.

2 Answers2

2
@ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
:: remove variables starting $ or #
For %%b IN ($ #) DO FOR  /F "delims==" %%a In ('set %%b 2^>Nul') DO SET "%%a="

SET /a count=0
SET "select=this is select's original value"

ECHO parameters received = %*

:loop
REM SET $... and #... to the parameter-pair.
SET $%count%=%1
SET #%count%=%2
IF NOT DEFINED $%count% GOTO process
IF NOT DEFINED #%count% ECHO "Incomplete pair"&GOTO :EOF
SET /a count +=1
:: shift twice to move 2 parameters
shift&shift&GOTO loop

:process
ECHO %count% pairs found
SET $
SET #

FOR /L %%a IN (1,1,%count%) DO (
 REM note that this changes "select"
 SET /a select=%%a - 1
 CALL SET /a item1=%%$!select!%%
 CALL SET /a item2=%%#!select!%%

 ECHO pair %%a is !item1! and !item2! from $!select! and #!select! NOT $#%select%
)

ECHO ----------------- select = %select% ----------
SET /a count-=1

FOR /L %%a IN (0,1,%count%) DO (
 REM note that this changes "select"
 SET /a select=%%a + 1

 ECHO pair !select! is !$%%a! and !#%%a! from $%%a and #%%a NOT $#%select%

GOTO :EOF

First, set up some initial values. The first for ensures that any variables starting $ or # are cleared.

Set $0 and #0 to the first and second parameters. If $0 is not set, then we have no further data, so process what we have. If $0 is set but #0 is not, we don't have a pair so complain and terminate.

If both #0 ans $0 are set, increment count, shift the parameters twice and run around the loop. The next pair will be placed in $/#1 and so on until the parameters are exhausted.

Now show the count of parameters and the $ and # values that have been set.

Next loop show unnecessary manipulation of the variables.

  • First set select to 1 less than the loop-counter.
  • then use a parsing trick to get the value of $[current value of select]. The line translates to "SET /a item1=%$n%" where n is the run-time value of select - ie. the value as it changes through the loop.
  • then show the results. item1 is changed within the block (parenthesised series of statements) so we need !item1 to access that changed value - %item1% would give us the value as it was when the loop was parsed. You can see that from the report for select on the same line.

Last loop is the same idea - but varying %%a from 0 to (count-1). Observe that select in the dashed echo line has the last value it was assigned in the previous loop.

So, once again we change select within the block, so we see a difference between !select! and %select%. We can also access $0 directly using !$%%a! - that is the current value of the variable [$ strung with the current value of the loop-control %%a]

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • Thanks for this answer. There was only one issue. From what I understand `set /a` only stores numeric values. What if my arguments are strings? (I am refering to `set /a item1` and `set /a item2`) – Alex Stacks Feb 01 '16 at 21:23
  • also what does `SETLOCAL ENABLEDELAYEDEXPANSION` do? – Alex Stacks Feb 01 '16 at 21:27
  • I am sorry. these^ were my comments. I was logged into my brother's account –  Feb 01 '16 at 21:29
  • 1
    Certainly. Use the syntax `set "varname=%~1"` to assign a string instead. It will work just the same. Batch actually only uses strings. The `~` strips any enclosing `"` from the element, so you coud invoke *yourbatch* 3 "some item" for instance. Note that the quotes in the `set` command I've mentioned ensure that any trailing spaces on the batch line are not included in the value assigned (which can be hard-to-find) – Magoo Feb 01 '16 at 21:30
0
@echo off
setlocal EnableDelayedExpansion

rem Store arguments one by one
set "count=0"
:repeat
   set /A count+=1
   set "param[%count%]=%~1"
   shift
if "%~1" neq "" goto repeat

rem Show arguments in pairs
set /A countMIN1=count-1
for /L %%i in (1,2,%countMIN1%) do (
   set /A j=%%i+1
   for %%j in (!j!) do echo !param[%%i]! !param[%%j]!
)

For further details, see: Arrays, linked lists and other data structures in cmd.exe (batch) script

Community
  • 1
  • 1
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • I am sorry. I am very new to batch. Could you explain to me what you did, so I can understand? – Alex Stacks Feb 01 '16 at 21:26
  • I am sorry. that^ was my comment. I was logged into my brother's account –  Feb 01 '16 at 21:28
  • 1
    The first part is your same code, where you create the "param" array with all arguments. In the second part `%%i` is varied as `1,3,5,...` up to N-1, and j is %%i+1, so the `echo !param[%%i]! !param[%%j]!` command show params 1 and 2 first, then params 3 and 4, etc... – Aacini Feb 01 '16 at 21:37