Reputation: 18084
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
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.
~
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
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
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
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
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