Is there a way to indicate the last n parameters in a batch file?

Solution 1:

%* will always expand to all original parameters, sadly. But you can use the following snippet of code to build a variable containing all but the first parameter:

rem throw the first parameter away
shift
set params=%1
:loop
shift
if [%1]==[] goto afterloop
set params=%params% %1
goto loop
:afterloop

I think it can be done shorter, though ... I don't write these sort of things very often :)

Should work, though.

Solution 2:

Here's a one-line approach using the "for" command...

for /f "usebackq tokens=1*" %%i in (`echo %*`) DO @ set params=%%j

This command assigns the 1st parameter to "i" and the rest (denoted by '*') are assigned to "j", which is then used to set the "params" variable.

Solution 3:

Warning! this method has side-effect of expanding wildcards, if there are «*»s or «?»s in the arguments. If there is a wildcard but no corresponding files, argument is skipped (non-wildcard arguments stay as-is). If arguments must stay intact, look for another way.


the line

%CMD% <WHAT DO I PUT HERE>

shall be changed to:

(
  SETLOCAL ENABLEDELAYEDEXPANSION
  SET skip=1

  FOR %%I IN (%*) DO IF !skip! LEQ 0 (
        SET "params=!params! %%I"
    ) ELSE SET /A skip-=1
)
(
  ENDLOCAL
  SET "params=%params%"
)
%CMD% %params%

of course, you may set skip var to any number of arguments.

Explaned:

(
@rem Starting block here, because it's read once and executed as one
@rem otherwise cmd.exe reads file line by line, which is waaay slower.

SETLOCAL ENABLEDELAYEDEXPANSION
SET skip=1

@rem if value contains unquoted non-paired parenthesis, SET varname=value 
@rem confuses cmd.exe. SET "a=value" works better even if value has quotes.
  FOR %%I IN (%*) DO (
    IF !skip! LEQ 0 (
      SET "params=!params! %%I"
      @rem newline after SET to lower amount of pitfalls when arguments 
      @rem have unpaired quotes
    ) ELSE (
      SET /A skip-=1
    )
)
(
@rem get variables out of SETLOCAL block
@rem as whole block in parenthesis is read and expanded before executing,
@rem SET after ENDLOCAL in same block will set var to what it was before
@rem ENDLOCAL. All other envvars will be reset to state before SETLOCAL.
ENDLOCAL
SET "params=%params%"
)
@rem doing this outside of parenthesis block to avoid
@rem cmd.exe confusion if params contain unquoted closing round bracket
%CMD% %params%

Solution 4:

You can actually just do this:

%*

If that is the only thing on the line, then that expands to having the first parameter be the command executed, with all other parameters passed to it. :)