Ignoring Arguments

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
atfon
Posts: 178
Joined: 06 Oct 2017 07:33

Ignoring Arguments

#1 Post by atfon » 26 Aug 2021 13:28

I have a batch script which can be run either interactively or through the use of command line arguments. I use switches like /a to define the argument. It works fine. It ignores if there isn't a slash "/" or "-" for the switch. It will invalidate an argument that doesn't exist. I have just been debugging to see if I could cause behavior I did not want. I noticed that if I followed a valid switch with a space and then some text, it opens the script in interactive mode, which I do not want. Is there a way to block additional arguments beyond the valid set?

This is where I check if the script is run interactively (double-click):

Code: Select all

if "%~1"=="" (
cls
call :env
goto :menu
)
I'm then checking for valid arguments:

Code: Select all

if "!switch!" equ "/p" (
    cls
    call :printer
  ) else if "!switch!" equ "/o" (
    cls
    call :os
  ) else if "!switch!" equ "/q" (
    cls
    call :general
  ) else (
    cls
    echo Please enter a valid switch. Type info.bat /? for a list of available switches.
    exit /b
  )
In this case, typing "info.bat /p 5" will open the script interactively. Thanks in advance for any suggestions you might have.

T3RRY
Posts: 243
Joined: 06 May 2020 10:14

Re: Ignoring Arguments

#2 Post by T3RRY » 26 Aug 2021 22:17

One option is to use a for loop with a list of valid switches to set a flag variable true if the current arg is a valid switch, then assign the next parameter as the switch value.

Switch values should always be doublequoted to guard against posion characters and to ensure whole strings containing standard delims are correctly captured as the switch value.
The alternative would be to use a series of substring modifications to identify the start of the next switch in the arg string and seperate the switch value, however there are more issues with characters that are not handled by substring modification then there is by using shift with a loop.

Note: the use of Call to forward the arg string doubles any Carets in switch values.

an example:

Code: Select all

@Echo off

Setlocal EnableExtensions
 Call :GetArgs %*
 If not errorlevel 1 Echo(Your usage info here
 Set Switch[ 2> nul

Endlocal & Goto :eof

=============================================
:GetArgs REM define valid_Switches list below
 Set valid_Switches="/a" "/b" "/c" "/f" "-a" "-b" "-c" "-f"

 If "%~1"=="" Exit /B 0
 For /f "tokens=1 Delims==" %%G in ('Set "Switch[" 2^> nul')Do Set "%%~G="
 Set "?Switch{I}=0"

:processSwitches
 If "%~1"=="" Exit /B %?Switch{I}%
 Set "?Switch_Name=%~1"
 Set "?Switch_Valid="
 Set "?Switch_NoSubArg="
 For %%G in (%valid_Switches%)Do If "%%~G"=="%~1" (
  Call :Verify "%~2"
  If not errorlevel 1 (
   Set "?Switch_Valid=t"
   Set /A "?Switch{I}+=1"
  )Else (
   Set "?Switch_NoSubarg=t"
   Set /A "?Switch{I}+=1"
  )
 )
 If Defined ?Switch_Valid Set "Switch[%?Switch_Name:~1%]=%~2"
 If Defined ?Switch_NoSubarg Set "Switch[%?Switch_Name:~1%]=true"
 Shift
Goto :processSwitches

:Verify
%= Handle last switch with no Subarg =%
 If "%~1"=="" Exit /b 1
%= Handle Switch with no Subarg followed by another Switch =%
 For %%V in (%valid_Switches%)Do If "%%~V"=="%~1" Exit /b 1
%= Flag Switch as trailed by Subarg =%
 Exit /b 0
To handle Args as well as switches with / without subargs:

Code: Select all

@Echo off & Cls

Setlocal EnableExtensions
 Call :GetArgs %*
 If not errorlevel 1 (
  Echo(No Valid Switches detected.
  Echo(%Valid_Switches:"=%
 )
 Set Switch[ 2> nul
 Set Arg[ 2> nul

Endlocal & Goto :eof

======================================
:GetArgs <%*>
%= Example define valid_Switches list below =%
 Set valid_Switches="/a" "/b" "/c" "/f" "-a" "-b" "-c" "-f"

 If "%~1"=="" Exit /B 0
 For /f "tokens=1 Delims==" %%G in ('Set "Switch[" 2^> nul')Do Set "%%~G="
 For /f "tokens=1 Delims==" %%G in ('Set "Arg[" 2^> nul')Do Set "%%~G="
 Set "?Switch{I}=0"
 Set "?Arg=0"
   Set "?Switch_Encountered="

:processSwitches
 If "%~1"=="" Exit /B %?Switch{I}%
 Set "?Switch_Name=%~1"
 Set "?Switch_Valid="
 Set "?Switch_NoSubArg="
 For %%G in (%valid_Switches%)Do If "%%~G"=="%~1" (
  Set "?Switch_Encountered=True"
  Call :Verify "%~2"
  If not errorlevel 1 (
   Set "?Switch_Valid=t"
   Set /A "?Switch{I}+=1"
  )Else (
   Set "?Switch_NoSubarg=t"
   Set /A "?Switch{I}+=1"
  )
 )

%= Define Switch[letter] with subarg value =%
 If Defined ?Switch_Valid Set "Switch[%?Switch_Name:~1%]=%~2"
%= Define Switch[letter] as true - used with no subarg =%
 If Defined ?Switch_NoSubarg Set "Switch[%?Switch_Name:~1%]=true"

%= Capture args preceeding switches as array =%
 If not defined ?Switch_Encountered (
  Set /A "?Arg{I}+=1"
  For /f "Tokens=2 delims==" %%v in ('Set "?Arg{I}"')Do Set "Arg[%%v]=%~1"
 )

 Shift
Goto :processSwitches

:Verify
%= Handle last switch with no Subarg =%
 If "%~1"=="" Exit /b 1
%= Handle Switch with no Subarg followed by another Switch =%
 For %%V in (%valid_Switches%)Do If "%%~V"=="%~1" Exit /b 1
%= Flag Subvalue as invalid Switch =%
 <nul Set /P "=%~1"|%__APPDIR__%Findstr.exe /ri "^[/-][abcdefghijklmnopqrstuvwxyz]*" > nul 2> nul && Exit /b 1
%= Flag Switch as trailed by Subarg =%
 Exit /b 0
Last edited by T3RRY on 27 Aug 2021 06:43, edited 2 times in total.

atfon
Posts: 178
Joined: 06 Oct 2017 07:33

Re: Ignoring Arguments

#3 Post by atfon » 27 Aug 2021 06:06

Hi T3RRY. Thank you for your feedback and suggested code. I will study it up and see how I can incorporate the elements I need.

T3RRY
Posts: 243
Joined: 06 May 2020 10:14

Re: Ignoring Arguments

#4 Post by T3RRY » 27 Aug 2021 06:20

atfon wrote:
27 Aug 2021 06:06
Hi T3RRY. Thank you for your feedback and suggested code. I will study it up and see how I can incorporate the elements I need.
As a function, its a simple addition. Switches used are returned to an array Switch[letter] with letters being sourced from the defined valid_Switches variable
Note: Valid switches need not be single letters, however should not contain standard delimiters.

If for example the file is called with the parameters: /a -c /f 7
The following definitions willl occur
Switch[a]=true
Switch[c]=true
Switch[f]=7

Simply assess the value of the relevant switch after calling :GetArgs to perform the conditional executions you desire.

The second version also builds an array of any args that preceede switch usage and explicitly precludes the possibility of an invalid Switch IE: /False from
being defined as the subarg value to a valid switch.
Last edited by T3RRY on 27 Aug 2021 06:45, edited 3 times in total.

atfon
Posts: 178
Joined: 06 Oct 2017 07:33

Re: Ignoring Arguments

#5 Post by atfon » 27 Aug 2021 06:33

As a function, its a simple addition.
This may be true, but I'm no expert at batch scripting and I like to study the code so it meets my needs. For example, I may decide I want to limit switches to only one. Plus, I still want the file to launch with the name of the batch alone or by double-clicking in interactive mode.

Anyhow, that you again for your time and effort.

T3RRY
Posts: 243
Joined: 06 May 2020 10:14

Re: Ignoring Arguments

#6 Post by T3RRY » 27 Aug 2021 06:53

atfon wrote:
27 Aug 2021 06:33
For example, I may decide I want to limit switches to only one.

I'm sure the following is self explanatory with regards to how to maintain or modify what switches you wish to accept

Code: Select all

%= Example define valid_Switches list below =%
 Set valid_Switches="/a" "/b" "/c" "/f" "-a" "-b" "-c" "-f"
And a count of Switches used is returned in the variable: ?Switch{I}
atfon wrote:
27 Aug 2021 06:33
Plus, I still want the file to launch with the name of the batch alone
In the second version, args that precede switches [even if no switches are used] are defined to an arg array, the count of which is returned in: ?Arg{I}
atfon wrote:
27 Aug 2021 06:33
or by double-clicking in interactive mode.
The assement following the call to :GetArgs in the above examples is for example purposes only. getArgs returns silently regardless of arg / switch usage.
the value of the variables ?Switch{I} and ?Arg{I} are available for assement to determine how many, if any, arguments or switches the script was called with, prior to you assessing the values of those Args or Switches.

atfon
Posts: 178
Joined: 06 Oct 2017 07:33

Re: Ignoring Arguments

#7 Post by atfon » 27 Aug 2021 07:07

I'm sure the following is self explanatory with regards to how to maintain or modify what switches you wish to accept
I apologize. I misspoke. I meant I may limit how many switches I wish to accept, not which switches I wish to accept. I'm reviewing your script and some other script I have found on this forum which utilize argument switches.

T3RRY
Posts: 243
Joined: 06 May 2020 10:14

Re: Ignoring Arguments

#8 Post by T3RRY » 27 Aug 2021 07:52

atfon wrote:
27 Aug 2021 07:07
I'm sure the following is self explanatory with regards to how to maintain or modify what switches you wish to accept
I apologize. I misspoke. I meant I may limit how many switches I wish to accept, not which switches I wish to accept. I'm reviewing your script and some other script I have found on this forum which utilize argument switches.
If you want to Exclude subsequent switches after one is defined, I'm sure you'll see where you need to add an "exit /b 1"
Alternately, you could modify the definition of the Switch[index] array to use the ?Switch{I} count instead of the Switch letter and just use the value of Switch[1]

I can't guess the order of priority you wish to place on switch assessment [ If you have multiple permitted switches but only want to accept one, how do you decide which to keep? ]
The list form of valid_Switches makes it easy for you to implement priority by defining the Valid_Switches variable in the order of importance, regardless of which of the two exclusion approaches described above you choose.

Theres also the choice of modifying the switch array definition to support both count and letter indexing:

Code: Select all

@Echo off

%= Example. define valid_Switches variable for your script as doublequoted list below =%
 Set valid_Switches="/a" "/b" "/col" "/f" "-a" "-b" "-col" "-f"

Setlocal EnableExtensions
 Call :GetArgs %*
 If %Errorlevel% EQU 0 (
%= To notify usage in event of no args or switches remove rem below =%
   Rem For %%G in (%Valid_Switches:" "=|%)Do Echo(No paramaters. %~n0 [Args] [%%~G]
 )

 Set Switch[ 2> nul
 Set Arg[ 2> nul

Pause
Endlocal & Goto :eof

======================================
:GetArgs <%*>
:: Return values:
:: Errorlevel 0 No Args, No Switches
:: ?Arg{I} Count of Arguments
:: ?Switch{I} Count of Switches used
:: Arg[i] Index Argument value at position i
:: Switch.i Index Switch value at position i
:: Switch[string] Index value of /String or -String defined in valid_Switches [true if used without subarg; else subargs value]

 If not defined Valid_Switches (
  Echo(Define Valid_Switches Variable prior to calling %~n0 
  Pause
  Exit
 )
 If "%~1"=="" Exit /B 0
 For /f "tokens=1 Delims==" %%G in ('Set "Switch" 2^> nul')Do Set "%%~G="
 For /f "tokens=1 Delims==" %%G in ('Set "Arg[" 2^> nul')Do Set "%%~G="
 Set "?Switch{I}=0"
 Set "?Arg{I}=0"
 Set "?Switch_Encountered="

:processParams
 If "%~1"=="" Exit /B 1
 Set "?Switch_Name=%~1"
 Set "?Switch_Valid="
 Set "?Switch_NoSubArg="
 For %%G in (%valid_Switches%)Do If "%%~G"=="%~1" (
  Set "?Switch_Encountered=true"
  Call :Verify "%~2"
  If not errorlevel 1 (
   Set "?Switch_Valid=t"
   Set /A "?Switch{I}+=1"
  )Else (
   Set "?Switch_NoSubarg=t"
   Set /A "?Switch{I}+=1"
  )
 )

%= Define Switch[letter] with subarg value =%
 If Defined ?Switch_Valid (
  Set "Switch[%?Switch_Name:~1%]=%~2"
  For /f "Tokens=2 delims==" %%v in ('Set "?Switch{I}"')Do Set "Switch.%%v=%~2"
 )
%= Define Switch[letter] as true - used with no subarg =%
 If Defined ?Switch_NoSubarg (
  Set "Switch[%?Switch_Name:~1%]=true"
  For /f "Tokens=2 delims==" %%v in ('Set "?Switch{I}"')Do Set "Switch.%%v=true"
 )

%= Capture args preceeding switches as array =%
 If not defined ?Switch_Encountered (
  %= Exclude invalid switch pattern =%
  Call :Verify "%~1" 
  If not Errorlevel 1 (
   Set /A "?Arg{I}+=1"
   For /f "Tokens=2 delims==" %%v in ('Set "?Arg{I}"')Do Set "Arg[%%v]=%~1"
  )
 )

 Shift
Goto :processParams

:Verify
%= Handle last switch with no Subarg =%
 If "%~1"=="" Exit /b 1
%= Handle Switch with no Subarg followed by another Switch =%
 For %%V in (%valid_Switches%)Do If "%%~V"=="%~1" Exit /b 1
%= Flag Subvalue as invalid Switch if SINGLE LETTER =%
  <nul Set /P "=%~1"|%__APPDIR__%Findstr.exe /ri "^[/-][abcdefghijklmnopqrstuvwxyz]$" > nul 2> nul && (
  %= Terminate Arg array definition on encountering invalid switch =%
  Set "?Switch_Encountered=true"
  Exit /b 1
 )
%= Flag Switch as trailed by Subarg =%
 Exit /b 0

atfon
Posts: 178
Joined: 06 Oct 2017 07:33

Re: Ignoring Arguments

#9 Post by atfon » 30 Aug 2021 07:27

Since I am currently only going to accept a single argument, I ended up using a less robust solution than T3RRY suggested. If at a later time I decide to allow for additional arguments, I will revisit this topic again. Once more, thank you T3RRY for all your helpful suggestions. This is an abbreviated version what I ended up using. I'm sure there are plenty of holes in it, but it seems to meet my needs for now:

Code: Select all

@echo off
setlocal enabledelayedexpansion
if "%~1"=="" (
cls
call :env
goto :banner
)
if .%2 equ . (
  set "switch=%~1"
  if "!switch:~0,1!" equ "-" set "switch=/!switch:~1!"
  if "!switch:~0,1!" neq "/" (
    cls
    echo Please enter a valid switch. 
    exit /b
  )
  if "!switch!" equ "/p" (
    cls
    call :printer
  ) else if "!switch!" equ "/o" (
    cls
    call :os
  ) else if "!switch!" equ "/q" (
    cls
    call :general
  ) else (
    cls
    echo Please enter a valid switch.
    exit /b
  )
)
if .%3 geq . (
  cls
  echo Please enter only one valid switch.
  exit /b
)

Squashman
Expert
Posts: 4465
Joined: 23 Dec 2011 13:59

Re: Ignoring Arguments

#10 Post by Squashman » 30 Aug 2021 11:28

This topic may be of interest to you as well.
foolproof counting of arguments

atfon
Posts: 178
Joined: 06 Oct 2017 07:33

Re: Ignoring Arguments

#11 Post by atfon » 30 Aug 2021 11:41

Thanks, Squashman! That is an interesting discussion.

**Slightly off topic. Do you folks have a reliable method you use to search this forum? I find the phpBB forum search features could be better.***

Squashman
Expert
Posts: 4465
Joined: 23 Dec 2011 13:59

Re: Ignoring Arguments

#12 Post by Squashman » 30 Aug 2021 11:54

atfon wrote:
30 Aug 2021 11:41
**Slightly off topic. Do you folks have a reliable method you use to search this forum? I find the phpBB forum search features could be better.***
I always use Google.
arguments site:dostips.com

atfon
Posts: 178
Joined: 06 Oct 2017 07:33

Re: Ignoring Arguments

#13 Post by atfon » 30 Aug 2021 12:15


Post Reply