matt wilkie
matt wilkie

Reputation: 18084

how to get batch file parameters from Nth position on?

Further to How to Pass Command Line Parameters in batch file how does one get the rest of the parameters with specifying them exactly? I don't want to use SHIFT because I don't know how many parameters there might be and would like to avoid counting them, if I can.

For example, given this batch file:

@echo off
set par1=%1
set par2=%2
set par3=%3
set therest=%???
echo the script is %0
echo Parameter 1 is %par1%
echo Parameter 2 is %par2%
echo Parameter 3 is %par3%
echo and the rest are %therest%

Running mybatch opt1 opt2 opt3 opt4 opt5 ...opt20 would yield:

the script is mybatch
Parameter 1 is opt1
Parameter 2 is opt2
Parameter 3 is opt3
and the rest are opt4 opt5 ...opt20

I know %* gives all the parameters, but I don't wan't the first three (for example).

Upvotes: 22

Views: 36913

Answers (5)

Thomas Oatman
Thomas Oatman

Reputation: 321

One more alternative :-)

some of the other answers did not deal with quotes, or with extra spaces between parameters. Disclaimer: I have not tested this extremely well.

This is all just a workaround for %* not being updated after a shift ugg!

I implemented it as a POP starting from the technique by @Pavel-P.

  • It relies on the batch parser to remove extra spaces
  • It depends on a global variable 'Params'
  • ~ removes quotes -- leaving it up to you to re-quote as desired. Remove the ~ if you don't want that.
:PopFirstParam
    @set varname=%~1
    @set %varname%=%~2
    @rem @echo %varname% = '!%varname%!'
    @if '%3' equ '' set Params=&goto :eof
    @call :popone %Params%
@goto :eof
:popone
    @set Params=;;;%*
    @set Params=!Params:;;;%1 =!
@goto :eof

Usage:

@setlocal enabledelayedexpansion
@set Params=%*
@call :PopFirstParam P1 %Params%
@call :PopFirstParam P2 %Params%
@call :PopFirstParam P3 %Params%
@call :PopFirstParam P4 %Params%
@rem etc . . .

Specifically I use it to optionally run commands asynchronously:

@setlocal enabledelayedexpansion
@rem set variables that decide what to be run  . . . . 

@call :RunIfDefined doNum1 "Title 1"      mycmd1.exe     some  "params"   here
@call :RunIfDefined doNum2 "MyTitle 2"    mylongcmd2.exe some  "params"   here
@call :RunIfDefined doNum3 "Long Title 3" mycmd3.exe     some  "params"   here
@goto :eof

:RunIfDefined
    @set Params=%*
    @call :PopFirstParam DefineCheck %Params%
    @if not defined %DefineCheck% goto :eof
    
    @call :PopFirstParam WindowTitle %Params%
    @call :PopFirstParam Command %Params%
    @rem %Params% should now be the remaining params (I don't care about spaces here)
    @echo start "%WindowTitle%" "%Command%" %Params%
    @start "%WindowTitle%" "%Command%" %Params%
@goto :eof
C:\test> set doNum1=yes
C:\test> set doNum3=yes
C:\test> call dothings.bat

start "Title 1" "mycmd1.exe"     some  "params"   here
start "Long Title 3" "mycmd3.exe"     some  "params"   here

too bad DOS doesn't have a #include

Upvotes: 1

Pavel P
Pavel P

Reputation: 16843

@echo off
setlocal enabledelayedexpansion

set therest=;;;;;%*
set therest=!therest:;;;;;%1 %2 %3 =!

echo the script is %0
echo Parameter 1 is %1
echo Parameter 2 is %2
echo Parameter 3 is %3
echo and the rest are: %therest%

This works with quoted arguments and with arguments that have equal signs or commas, as long as first three arguments didn't have these special delimiter chars.

Sample output:

test_args.bat "1 1 1" 2 3 --a=b "x y z"
Parameter 1 is "1 1 1"
Parameter 2 is 2
Parameter 3 is 3
and the rest are: --a=b "x y z"

This works by replacing %1 %2 %3 in original command line %*. The first five semicolons are there just to make sure that only the first occurrence of these %1 %2 %3 is replaced.

Upvotes: 5

Ntats
Ntats

Reputation: 1

@ECHO OFF
SET REST=
::# Guess you want 3rd and on.
CALL :SUBPUSH 3 %*
::# ':~1' here is merely to drop leading space.
ECHO REST=%REST:~1%
GOTO :EOF

:SUBPUSH
SET /A LAST=%1-1
SHIFT
::# Let's throw the first two away.
FOR /L %%z in (1,1,%LAST%) do (
  SHIFT
)
:aloop
SET PAR=%~1
IF "x%PAR%" == "x" (
  GOTO :EOF
)
ECHO PAR=%PAR%
SET REST=%REST% "%PAR%"
SHIFT
GOTO aloop
GOTO :EOF

I like to use subroutines instead of EnableDelayedExpansion. Above is extract from my dir/file pattern processing batch. Don't say this cannot handle arguments with =, but at least can do quoted path with spaces, and wildcards.

Upvotes: 1

aschipfl
aschipfl

Reputation: 34919

The following code uses shift, but it avoids to parse the command line using for and lets the command line interpreter do this job (regard that for does not parse double-quotes properly, for instance argument set A B" "C is interpreted as 3 arguments A, B", "C by for, but as 2 arguments A, B" "C by the interpreter; this behaviour prevents quoted path arguments like "C:\Program Files\" from being handled correctly):

@echo off

set "par1=%1" & shift /1
set "par2=%1" & shift /1
set "par3=%1" & shift /1

set therest=
set delim=

:REPEAT
if "%1"=="" goto :UNTIL
set "therest=%therest%%delim%%1"
set "delim= "
shift /1
goto :REPEAT
:UNTIL

echo the script is "%0"
echo Parameter 1 is "%par1%"
echo Parameter 2 is "%par2%"
echo Parameter 3 is "%par3%"
echo and the rest are "%therest%"
rem.the additional double-quotes in the above echoes^
    are intended to visualise potential whitespaces

The remaining arguments in %therest% might not look like the way they were originally concerning the delimiters (remember the command line interpreter also treats TABs, ,, ;, = as delimiters as well as all combinations), because all delimiters are replaced by a single space here. However, when passing %therest% to some other command or batch file, it will be parsed correctly.

The only limitation I encountered so far applies to arguments containing the caret character ^. Other limitations (related to <, >, |, &, ") apply to the command line interpreter itself.

Upvotes: 2

Patrick Cuff
Patrick Cuff

Reputation: 29806

Here's how you can do it without using SHIFT:

@echo off

for /f "tokens=1-3*" %%a in ("%*") do (
    set par1=%%a
    set par2=%%b
    set par3=%%c
    set therest=%%d
)

echo the script is %0
echo Parameter 1 is %par1%
echo Parameter 2 is %par2%
echo Parameter 3 is %par3%
echo and the rest are %therest%

Upvotes: 26

Related Questions