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

Parse unordered command-line switches?

297 views
Skip to first unread message

JJ

unread,
Dec 5, 2011, 3:26:39 PM12/5/11
to
For instance, say I wanted to allow switches such as /f (force) and /s
(silent) and others for controlling the actions within the batch
itself, without requiring them to be in a strict order so that they
appear within %1, %2, etc. Is there a way to parse them?

We'll keep it fairly simple. There are no 'unnamed' arguments - they
will all be preceded by a forward slash. They can all be single
characters with no variation (e.g. /f, /force). But there may be zero
or more and they be in any order.

Tom Lavedas

unread,
Dec 5, 2011, 4:08:02 PM12/5/11
to
Maybe something like this ...

echo %*| find /i "/f" > nul && set force=true !! set "force="
echo %*| find /i "/s" > nul && set silent=true !! set "silent="
echo %*| find "/?" > nul && goto help
if defined force (
echo do what FORCE switch requires
) else (
echo do something else
)
___________________________
Tom Lavedas

foxidrive

unread,
Dec 5, 2011, 4:23:05 PM12/5/11
to
Here is one way.
I'm assuming that /f and /force are the same switch.


@echo off
echo %*|find /i "/F" >nul && set swf=true
echo %*|find /i "/S" >nul && set sws=true
echo %*|find /i "/P" >nul && set swp=true

set sw

pause


--
Regards,
Mic

foxidrive

unread,
Dec 5, 2011, 4:24:40 PM12/5/11
to
Our solutions are in essence spookily similar, Tom. :)

--
Regards,
Mic

Tom Lavedas

unread,
Dec 5, 2011, 4:44:46 PM12/5/11
to
> Mic- Hide quoted text -
>
> - Show quoted text -

Maybe that means its the best one ;^)
______________________
Tom Lavedas

Timo Salmi

unread,
Dec 5, 2011, 10:20:16 PM12/5/11
to
On 05.12.2011 23:44 Tom Lavedas wrote:
> On Dec 5, 4:24 pm, foxidrive <foxidr...@gotcha.woohoo.invalid> wrote:
>> On 6/12/2011 08:08, Tom Lavedas wrote:
>> Our solutions are in essence spookily similar, Tom. :)
> Maybe that means its the best one ;^)

They instructive solutions. In a script one would also wish to ensure an
error if a non-intended switch were given to the script. There are
several ways for doing that. From your solutions one option is

@echo off & setlocal enableextensions
echo. %*|find /i "/f" >nul && set "swf=true" || set "swf="
echo. %*|find /i "/s" >nul && set "sws=true" || set "sws="
echo. %*|find "/?" >nul && (call :usage & goto :EOF)
echo swf=%swf%
echo sws=%sws%
echo. %*|find "/">nul^
&& if not defined swf if not defined sws (call :error & goto :EOF)
endlocal & goto :EOF

:error
echo Error: No valid switch on the command line
call :usage
goto :EOF

:usage
echo An explation of the usage
goto :EOF

Which still is a bit unpolished.

Parsing the command-line can be an involved task. Especially if there
are both parameters and switches. Some on that in
40} How to get the number of and parse the arguments given to a script?
http://www.netikka.net/tsneti/info/tscmd040.htm

All the best, Timo

--
Prof. (emer.) Timo Salmi, Vaasa, Finland
http://www.netikka.net/tsneti/homepage.php
Useful CMD script tricks http://www.netikka.net/tsneti/info/tscmd.php

Timo Salmi

unread,
Dec 5, 2011, 11:16:26 PM12/5/11
to
On 05.12.2011 22:26 JJ wrote:
> For instance, say I wanted to allow switches such as /f (force) and /s
> (silent) and others for controlling the actions within the batch
> itself, without requiring them to be in a strict order so that they
> appear within %1, %2, etc. Is there a way to parse them?

Another option, potentially easier to understand, is

@echo off & setlocal enableextensions
set par1=%~1
set par2=%~2
for %%p in (%par1% %par2%) do (if /i "%%p"=="/f" set force=true)
for %%p in (%par1% %par2%) do (if /i "%%p"=="/s" set silent=true)
rem ... whatever actions ...
endlocal & goto :EOF

Timo Salmi

unread,
Dec 6, 2011, 5:27:07 AM12/6/11
to
On 05.12.2011 23:44 Tom Lavedas wrote:
> On Dec 5, 4:24 pm, foxidrive <foxidr...@gotcha.woohoo.invalid> wrote:
>> On 6/12/2011 08:08, Tom Lavedas wrote:
>> Our solutions are in essence spookily similar, Tom. :)
> Maybe that means its the best one ;^)

I added an expose on these solutions and some further problem aspects to
http://www.netikka.net/tsneti/info/tscmd040.htm#five

Frank P. Westlake

unread,
Dec 6, 2011, 9:52:55 AM12/6/11
to
From JJ :
>For instance, say I wanted to allow switches such as /f
>(force) and /s
>(silent) and others for controlling the actions within
>the batch
>itself, without requiring them to be in a strict order
>so that they
>appear within %1, %2, etc. Is there a way to parse
>them?

I've been using this algorithm successfully for many years:

@Echo OFF
SetLocal EnableExtensions
:: Remove all '$' variables from local environment:
For /F "tokens=1 delims==" %%a in ('Set "$" 2^>NUL:') Do Set "%%a="
For /F "tokens=1 delims==" %%a in ('Set "#" 2^>NUL:') Do Set "%%a="
:: Script name for error output:
Set "$ME=%~n0"
:: Parse all arguments:
:args
:: I use '$' alone as a temporary variable throughout.
Set "$=%1"
:: Use 'IF /I' so they are not case sensative.
If /I "%$%" EQU "/S" (
Set "$Silent=1"
Shift
) Else If /I "%$%" EQU "/SILENT" (
Set "$Silent=1"
Shift
) Else If /I "%$%" EQU "/F" (
Set "$Force=1"
Shift
) Else If /I "%$%" EQU "/FORCE" (
Set "$Force=1"
Shift
) Else If /I "%$:~0,1%" EQU "/" (
(Echo %$ME%: Aborting, unknown parameter '%$%'.)>&2
Goto :EOF
) Else If DEFINED $argFile (
(Echo %$Me%: Aborting, too many filenames.)>&2
Goto :EOF
) Else (
Set "$argFile=%~f1"
Shift
)
IF "%1" NEQ "" Goto :args
:: For demonstration, view all script variables:
Set $
Set #

I use the prefix '$' for variable variables and the
prefix '#' for constant variables.

All parameters are parsed, case not significant, and
unknown parameters cause an abort. In the above demo an
argument not prefixed with '/' is assumed to be the name
of a file which will be used in the script.

Frank

--
Sent from an Android

Frank P. Westlake

unread,
Dec 6, 2011, 10:48:41 AM12/6/11
to
Additionally, a parameter which is followed by an argument may be tested
and assigned. I've inserted the addition below:

> @Echo OFF
> SetLocal EnableExtensions
> :: Remove all '$' variables from local environment:
> For /F "tokens=1 delims==" %%a in ('Set "$" 2^>NUL:') Do Set "%%a="
> For /F "tokens=1 delims==" %%a in ('Set "#" 2^>NUL:') Do Set "%%a="
> :: Script name for error output:
> Set "$ME=%~n0"
> :: Parse all arguments:
> :args
> :: I use '$' alone as a temporary variable throughout.
> Set "$=%1"
> :: Use 'IF /I' so they are not case sensative.
> If /I "%$%" EQU "/S" (
> Set "$Silent=1"
> Shift
> ) Else If /I "%$%" EQU "/SILENT" (
> Set "$Silent=1"
> Shift
> ) Else If /I "%$%" EQU "/F" (
> Set "$Force=1"
> Shift
> ) Else If /I "%$%" EQU "/FORCE" (
> Set "$Force=1"
> Shift

) Else If /I "%$%" EQU "/USERNAME" (
Set "$Username=%2"
Shift
Shift

> ) Else If /I "%$:~0,1%" EQU "/" (
> (Echo %$ME%: Aborting, unknown parameter '%$%'.)>&2
> Goto :EOF
> ) Else If DEFINED $argFile (
> (Echo %$Me%: Aborting, too many filenames.)>&2
> Goto :EOF
> ) Else (
> Set "$argFile=%~f1"
> Shift
> )
> IF "%1" NEQ "" Goto :args
> :: For demonstration, view all script variables:
> Set $
> Set #

Frank

Timo Salmi

unread,
Dec 7, 2011, 9:12:25 AM12/7/11
to
On 05.12.2011 23:08 Tom Lavedas wrote:
> echo %*| find "/?" > nul && goto help

You will probably by now observed that that line does not work, as I
point out in the updated FAQ item #40. The reason is unclear.

foxidrive

unread,
Dec 7, 2011, 9:28:26 AM12/7/11
to
On 8/12/2011 01:12, Timo Salmi wrote:
> On 05.12.2011 23:08 Tom Lavedas wrote:
>> echo %*| find "/?" > nul && goto help
>
> You will probably by now observed that that line does not work, as I
> point out in the updated FAQ item #40. The reason is unclear.

This works Timo - note the period at the end of echo

echo.%*| find "/?" > nul && goto help


The reason is /? is seen as a help syntax by echo

echo /?

It returns the helps screen and not "/?"


While dwelling on other possible points of failure /& and /^ are likely to be problematic.



--
Regards,
Mic

Timo Salmi

unread,
Dec 7, 2011, 11:24:37 AM12/7/11
to
On 07.12.2011 16:28 foxidrive wrote:
> This works Timo - note the period at the end of echo
> echo.%*| find "/?" > nul && goto help
> The reason is /? is seen as a help syntax by echo
> echo /?
> It returns the helps screen and not "/?"

Good catch. Slaps forehead. In retrospect, should have been obvious.

> While dwelling on other possible points of failure /& and /^ are likely to be problematic.

Let's consider this
@echo off & setlocal enableextensions
for %%p in (%~1 %~2 %~3) do echo %%p
endlocal & goto :EOF

BATCH /a /? /b
returns
/a
/b

Likewise
BATCH 1 * 3
returns
1
3

foxidrive

unread,
Dec 7, 2011, 8:21:05 PM12/7/11
to
On 8/12/2011 03:24, Timo Salmi wrote:
> On 07.12.2011 16:28 foxidrive wrote:
>> This works Timo - note the period at the end of echo
>> echo.%*| find "/?" > nul && goto help
>> The reason is /? is seen as a help syntax by echo
>> echo /?
>> It returns the helps screen and not "/?"
>
> Good catch. Slaps forehead. In retrospect, should have been obvious.
>
>> While dwelling on other possible points of failure /& and /^ are likely to be problematic.
>
> Let's consider this
> @echo off & setlocal enableextensions
> for %%p in (%~1 %~2 %~3) do echo %%p
> endlocal & goto :EOF
>
> BATCH /a /? /b
> returns
> /a
> /b
>
> Likewise
> BATCH 1 * 3
> returns
> 1
> 3

That is troublesome.

BATCH 1 * 3
returns this here
1
A.BAT
A.txt
batch.bat
compare date with cutoff day.BAT
Search and replace 2.bat
3



--
Regards,
Mic

Frank P. Westlake

unread,
Dec 12, 2011, 1:58:46 PM12/12/11
to
I'm submitting this "gist" as an experiment to see how it looks. Here is
a demo script for this topic:

<https://gist.github.com/1468570>

Github's gist system might be useful for some things this group does.

Frank
0 new messages