Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Get command line arguments 2 through ...

137 views
Skip to first unread message

JJ

unread,
Feb 27, 2008, 3:51:14 PM2/27/08
to
I have a batch file that has one required command line argument. I'd
like to be able to take any _additional_ arguments, #2 through n, and
pass them along to a prgram that the batch file executes.

Is there a convenient way to do this?

Harlan Grove

unread,
Feb 27, 2008, 4:11:56 PM2/27/08
to
JJ <jim.mca...@gmail.com> wrote...

for /F "tokens=1,*" %%a in ("%*") do (
set arg1st=%%a
set argrest=%%b
)
echo %%1: %arg1st%
echo rest: %argrest%

Timo Salmi

unread,
Feb 29, 2008, 6:10:38 AM2/29/08
to
Harlan Grove <hrl...@gmail.com> wrote:
> for /F "tokens=1,*" %%a in ("%*") do (
> set arg1st=%%a
> set argrest=%%b
> )
> echo %%1: %arg1st%
> echo rest: %argrest%

Nice, but breakable (what wouldn't be?)

C:\_D\TEST>HARLAN.CMD "1 "
The system cannot find the file
<>.
%1: "1
rest: "

The problem lies, not surprisingly, with quoted arguments.

Another, more complicated taking, but copping out using %~1

@echo off & setlocal enableextensions
rem enabledelayedexpansion

echo +----------------------------------------------------+
echo ^| CMD2DEMO.CMD Another selection of CMD syntax tips ^|
echo ^| By Prof. Timo Salmi http://lipas.uwasa.fi/~ts/ ^|
echo ^| Last modified Fri 29-Feb-2008 ^|
echo +----------------------------------------------------+
echo.
::
rem One frequent set of questions pertains to getting the first, rest,
rem and/or the last item in the arguments (replaceable parameters)
rem of a script call. Likewise, it is often asked how the parts of a
rem file path can be parsed. This generic demo does both (without
rem resorting to the special file-related FOR arguments handling).
::
rem This script file will part of the following collection:
rem ftp://garbo.uwasa.fi/pc/link/tscmd.zip
rem Useful NT/2000/XP script tricks and tips, T.Salmi
::
:: Get the string to be parsed, or use a demo default
set MyArguments=%~1
if "%~1"=="" set MyArguments=d:\folder 1\folder 2\folder 3
echo MyArguments=%MyArguments%
echo.
::
:: Choose the delims
echo %MyArguments%|find "\">nul
if %errorlevel% EQU 0 (set delims_=\) else (set delims_= )
::
:: Get the first part and the rest of a variable
for /f "tokens=1* delims=%delims_%" %%a in ("%MyArguments%") do (
set first_=%%a
set rest_=%%b
)
echo first_=%first_%
echo rest_ =%rest_%
::
:: Get the last part of a variable
set rest_=%MyArguments%
:_loop
for /f "tokens=1,* delims=%delims_%" %%a in ("%rest_%") do (
set rest_=%%b
set last_=%%a
if defined rest_ goto _loop
)
echo last_=%last_%
::
endlocal & goto :EOF

Example outputs
C:\_D\BAS>C:\_F\CMD\CMD2DEMO.CMD
+----------------------------------------------------+
| CMD2DEMO.CMD Another selection of CMD syntax tips |
| By Prof. Timo Salmi http://lipas.uwasa.fi/~ts/ |
| Last modified Fri 29-Feb-2008 |
+----------------------------------------------------+

MyArguments=d:\folder 1\folder 2\folder 3

first_=d:
rest_ =folder 1\folder 2\folder 3
last_=folder 3


C:\_D\BAS>C:\_F\CMD\CMD2DEMO.CMD "1 2 Whatever"
+----------------------------------------------------+
| CMD2DEMO.CMD Another selection of CMD syntax tips |
| By Prof. Timo Salmi http://lipas.uwasa.fi/~ts/ |
| Last modified Fri 29-Feb-2008 |
+----------------------------------------------------+

MyArguments=1 2 Whatever

first_=1
rest_ =2 Whatever
last_=Whatever

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FI-65101, Finland
Timo's Turbo Pascal FAQ from ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip

JJ

unread,
Feb 29, 2008, 7:35:01 AM2/29/08
to
On Feb 29, 4:10 am, Timo Salmi <t...@uwasa.fi> wrote:

> Harlan Grove <hrln...@gmail.com> wrote:
> > for /F "tokens=1,*" %%a in ("%*") do (
> >   set arg1st=%%a
> >   set argrest=%%b
> > )
> > echo %%1: %arg1st%
> > echo rest: %argrest%
>
> Nice, but breakable (what wouldn't be?)
>
> C:\_D\TEST>HARLAN.CMD "1 "
> The system cannot find the file
> <>.
> %1: "1
> rest: "
>
> The problem lies, not surprisingly, with quoted arguments.
>
> Another, more complicated taking, but copping out using %~1


Thanks to the both of you. Is there a way to create a more generic
function - one that could accept an integer parameter N and return the
arguments N+? Such a function could be dropped into different batch
scripts where there are a differing numbers of required arguments and
where you'd want to pass the rest along.

Timo Salmi

unread,
Feb 29, 2008, 11:10:47 AM2/29/08
to
JJ <jim.m...@gmail.com> wrote:
> Thanks to the both of you. Is there a way to create a more generic
> function - one that could accept an integer parameter N and return the
> arguments N+?

You might first wish to take a look in the related tricks in
40) How do I get the number of arguments given to a script?
207709 Feb 23 2008 ftp://garbo.uwasa.fi/pc/link/tscmd.zip
Http link format http://garbo.uwasa.fi/pub/pc/link/tscmd.zip
tscmd.zip Useful NT/2000/XP script tricks and tips, T.Salmi

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FI-65101, Finland

Timo's FAQ materials at http://www.uwasa.fi/~ts/http/tsfaq.html

Harlan Grove

unread,
Feb 29, 2008, 6:10:36 PM2/29/08
to
Timo Salmi <t...@uwasa.fi> wrote...

>Harlan Grove <hrln...@gmail.com> wrote:
>>for /F "tokens=1,*" %%a in ("%*") do (
>> set arg1st=%%a
>> set argrest=%%b
>>)
>>echo %%1: %arg1st%
>>echo rest: %argrest%
>
>Nice, but breakable (what wouldn't be?)
...

>The problem lies, not surprisingly, with quoted arguments.
>
>Another, more complicated taking, but copping out using %~1
...

Which has its own problems with comma or semicolons rather than
whitespace as argument separators.


> type simple.bat


@echo off & setlocal enableextensions

echo %%*: %*
set n=0
:LOOP
if "%~1" == "" goto :EOF
set /A n+=1
echo %%%n%: %1
shift
goto LOOP

> simple 1,2,3,4,5
%*: 1,2,3,4,5
%1: 1
%2: 2
%3: 3
%4: 4
%5: 5

> simple 1;2;3;4;5
%*: 1;2;3;4;5
%1: 1
%2: 2
%3: 3
%4: 4
%5: 5

> cmd2demo 1,2,3,4,5


+----------------------------------------------------+
| CMD2DEMO.CMD Another selection of CMD syntax tips |
| By Prof. Timo Salmi http://lipas.uwasa.fi/~ts/ |
| Last modified Fri 29-Feb-2008 |
+----------------------------------------------------+

MyArguments=1

first_=1
rest_ =
last_=1

> cmd2demo "1,2,3,4,5"


+----------------------------------------------------+
| CMD2DEMO.CMD Another selection of CMD syntax tips |
| By Prof. Timo Salmi http://lipas.uwasa.fi/~ts/ |
| Last modified Fri 29-Feb-2008 |
+----------------------------------------------------+

MyArguments=1,2,3,4,5

first_=1,2,3,4,5
rest_ =
last_=1,2,3,4,5


The devil is in the details, ain't it?

As far as I can see this would be a time for an expedient use of
VBScript, which is almost certainly available as cscript.exe on the
OP's machine.


@echo off & setlocal enableextensions

echo %%*: %*

if "%~2" == "" goto :EOF

set a1=%1
set a1="%a1:"=""%"

set a2=%2
set a2="%a2:"=""%"

set ar=%*
set ar="%ar:"=""%"

> %0.vbs echo ^
wscript.stdout.writeline mid(%ar%, instr(len(%a1%) + 1, %ar%, %a2%))

for /F "delims=" %%a in ('cscript //nologo %0.vbs') do set ar=%%a

echo %%1: %1
echo rest: %ar%

del %0.vbs


I'm sure this also breaks for some nastier command line arguments, but
it handles simple quoted arguments and all argument separators.

With regard to the OP's follow-up question, if the remaining command
line arguments are what's needed rather than the EXACT remaining
command line, e.g., given the arguments

first second third fourth fifth sixth,foo;bar

it'd be OK to represent the command line tail beginning with the 3rd
argument as

third fourth fifth sixth foo bar

then VBScript would again be expedient.


set n=3 & rem starting point for command line tail

> %0.vbs echo for n = %n% to wscript.arguments.count
>> %0.vbs echo a = a & " " & wscript.arguments(n - 1)
>> %0.vbs echo next
>> %0.vbs echo wscript.stdout.writeline mid(a, 2)

for /F "delims=" %%a in ('cscript //nologo %0.vbs') do set ar=%%a
del %0.vbs

Timo Salmi

unread,
Mar 1, 2008, 2:09:56 AM3/1/08
to
Harlan Grove <hrl...@gmail.com> wrote:

> Timo Salmi <t...@uwasa.fi> wrote...


>> Another, more complicated taking, but copping out using %~1

> Which has its own problems with comma or semicolons rather than
> whitespace as argument separators.

Which, fortunately, is easily remedied by elaborating the delims test.
Or, of course, more usually by fixing in advance what the delims are.

::
:: Choose the delims
(set delims_= )
echo %MyArguments%|find "\">nul
if %errorlevel% EQU 0 set delims_=\
echo %MyArguments%|find ",">nul
if %errorlevel% EQU 0 set delims_=,%delims_%
echo %MyArguments%|find ";">nul
if %errorlevel% EQU 0 set delims_=;%delims_%
::

Incidentally, note that it is imperative to have e.g. ,%delims_% instead
of %delims_%,

> @echo off & setlocal enableextensions
> echo %%*: %*
> set n=0
> :LOOP
> if "%~1" == "" goto :EOF
> set /A n+=1
> echo %%%n%: %1
> shift
> goto LOOP

In fact, a shift solution is what I suggest since ages in my FAQ item
40. It makes available argc and argv[i] (i=1,...,argc) which renders
the op-asked variations possible to solve in a rather generic manner.
Quoting from #40

The output might be e.g.
C:\_D\TEST>cmdfaq a b c "d e"
argc=4
argv[1]=a
argv[2]=b
argv[3]=c
argv[4]=d e

> The devil is in the details, ain't it?

Yes. Thanks for the examples.

> As far as I can see this would be a time for an expedient use of
> VBScript, which is almost certainly available as cscript.exe on the
> OP's machine.

VBS has more power. And having different options always is good.
Obviously could also be done with gawk. This time I went for a
non-third-party, non-VBS option.

Timo Salmi

unread,
Mar 1, 2008, 12:33:59 PM3/1/08
to
One, ugly option

@echo off & setlocal enableextensions enabledelayedexpansion
set n=0
if not "%~1"=="" (set p[1]=%~1&set n=1)
if not "%~2"=="" (set p[2]=%~2&set n=2)
if not "%~3"=="" (set p[3]=%~3&set n=3)
if not "%~4"=="" (set p[4]=%~4&set n=4)
if not "%~5"=="" (set p[5]=%~5&set n=5)
if not "%~6"=="" (set p[6]=%~6&set n=6)
if not "%~7"=="" (set p[7]=%~7&set n=7)
if not "%~8"=="" (set p[8]=%~8&set n=8)
if not "%~9"=="" (set p[9]=%~9&set n=9)
echo n=%n%
for /L %%i in (1,1,9) do echo p[%%i]=!p[%%i]!
for /L %%i in (2,1,9) do if defined p[%%i] set rest_=!rest_! !p[%%i]!
echo rest_=%rest_%
endlocal & goto :EOF

C:\_D\BAS>cmdfaq 1 2;3,4 "Hello world"
n=5
p[1]=1
p[2]=2
p[3]=3
p[4]=4
p[5]=Hello world
p[6]=
p[7]=
p[8]=
p[9]=
rest_= 2 3 4 Hello world

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FI-65101, Finland

Useful script files and tricks ftp://garbo.uwasa.fi/pc/link/tscmd.zip

foxidrive

unread,
Mar 1, 2008, 10:52:38 PM3/1/08
to
On Sat, 01 Mar 2008 19:33:59 +0200, Timo Salmi <t...@uwasa.fi> wrote:

>One, ugly option

This is a little nicer Timo. It handles ! characters and retains quoted
command line entries.

@echo off
for %%a in (%*) do set /a n=n+1&(call set p[%%n%%]=%%a)
echo Number of entries=%n%

for /L %%a in (1,1,100) do (
if defined p[%%a] call echo p[%%a]=%%p[%%a]%%)

for /L %%a in (2,1,100) do if defined p[%%a] (
call set rest_=%%rest_%% %%p[%%a]%%)
echo rest_=%rest_%


===[screen capture]===
Number of entries=5


p[1]=1
p[2]=2
p[3]=3

p[4]="Hello World"
p[5]="a & b"
rest_= 2 3 "Hello World" "a & b"
===[screen capture]===


Timo Salmi

unread,
Mar 2, 2008, 2:52:54 AM3/2/08
to
foxidrive <got...@woohoo.invalid> wrote:
> This is a little nicer Timo. It handles ! characters and retains quoted
> command line entries.

Thanks! I forgot about the call-trick to replace delayed expansion. I'll
use something like this directly drawn from your ideas

@echo off & setlocal enableextensions disabledelayedexpansion
set n=0
for %%a in (%*) do (set /a n+=1)&(call set p[%%n%%]=%%a)
::
echo n=%n%
for /L %%i in (1,1,9) do if defined p[%%i] call echo p[%%i]=%%p[%%i]%%
for /L %%i in (2,1,9) do if defined p[%%i] call set rest_=%%rest_%%
%%p[%%i]%%
if defined rest_ set rest_=%rest_:~1%


echo rest_=%rest_%
endlocal & goto :EOF

And, indeed
C:\_D\TEST>cmdfaq 1 2 3 "Hello World" "a & b"
n=5


p[1]=1
p[2]=2
p[3]=3
p[4]="Hello World"
p[5]="a & b"

rest_=2 3 "Hello World" "a & b"

0 new messages