[ACCEPTED]-Is there a way to indicate the last n parameters in a batch file?-cmd

Accepted answer
Score: 80

%* will always expand to all original parameters, sadly. But 5 you can use the following snippet of code 4 to build a variable containing all but the 3 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 2 ... I don't write these sort of things very 1 often :)

Should work, though.

Score: 17

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

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

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

Score: 10

Warning! this method has side-effect of expanding 7 wildcards, if there are «*»s or «?»s in 6 the arguments. If there is a wildcard but 5 no corresponding files, argument is skipped 4 (non-wildcard arguments stay as-is). If 3 arguments must stay intact, look for another 2 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 1 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%
Score: 7

You can actually just do this:

%*

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

Score: 2

I have improved Moshe Goren's answer because 1 it didn't seem to work for me:

set _input=%*
call set params=%%_input:%1 =%%
@echo %params%
Score: 1

Another way (almost the same as Alxander 11 Bird's) without executing ECHO in a subshell:

FOR /F "usebackq tokens=1*" %%I IN ('%*') DO SET params=%%J

so, line

%CMD% <WHAT DO I PUT HERE>

will 10 look like:

FOR /F "usebackq tokens=1*" %%I IN ('%*') DO %CMD% %%J

the problem is that if parameters 9 include quoted stings with spaces inside, cmd.exe 8 will parse them appropriately for using 7 as numbered arguments (%1), but FOR will 6 ignore the quotes. This specific case, it 5 will harm if first parameter includes a 4 space or more, which is quite possible, considering 3 first argument can be, for example, "C:\Program 2 Files\Internet Explorer\iexplore.exe".

So, here 1 will be another answer.

Score: 0

Although really the 'for' solution is superior 10 in a lot of circumstances, for something 9 simple I will frequently just save and shift 8 the other arguments away, then use %* as usual 7 (practically the same strategy often works 6 for $* or $@ in {,ba,da,k,*}sh):

example:

:: run_and_time_me.cmd - run a command with the arguments passed, while also piping
::                       the output through a second passed-in executable

@echo off

set run_me=%1
set pipe_to_me=%2
shift
shift

:: or
:: set run_me=%1
:: shift
:: set pipe_to_me=%1
:: shift

%run_me% %* | %pipe_to_me%

Anyhow, I saw the question 5 was long answered, but figured I'd drop 4 in my two cents as it was something I didn't 3 see, and because it was the answer I needed 2 when I finally happened across it a few 1 years back... and went "oh... duh." :)

Score: 0

I came across this question while I was 6 facing a similar problem, but I solved it 5 using a different approach. Instead of re-creating 4 the input line using a loop (as in the answer 3 by @Joey) I simply removed the first parameter 2 from the input string.

set _input=%*
set params=!_input:%1 =!
call OTHER_BATCH_FILE.cmd %params%

Of course, this assumes 1 that all the parameters are different.

More Related questions