Jump to content

Parse Commandline Parameters for CUI-App


cherdeg
 Share

Recommended Posts

Hi guys,

I'm currently doing a command line application that gets from 0, 1, 2 or 3 commandline parameters and does different things depending on these parameters. I want users to have a time as easy as possible when entering the parameters (foolproof). The parameters are all optional, but when used, some of them need additional information entered.

Examples for check.exe (information in <> is required):

check                               ...Checks all and everything with hardest settings
check -soft                         ...Checks all and everything with relaxed settings
check -med                          ...Checks all and everything with medium settings
check -single <hostname> -soft      ...Checks a single host <hostname> with relaxed settings
check -single <hostname> -med       ...Checks a single host <hostname> with medium settings
check -single <hostname> -hard      ...Checks a single host <hostname> with hardest settings
check -wg                           ...Checks all defined Workgroup-Machines with hardest settings
check -wg -hard                     ...Checks all defined Workgroup-Machines with hardest settings
check -wg -soft                     ...Checks all defined Workgroup-Machines with relaxed settings
check -ou <OUname>                  ...Checks all machines in the <OUname> with hardest settings
check -ou <OUname> -med             ...Checks all machines in the <OUname> with medium settings

You get it, I think. Point is a) to catch all input errors:

check -ou -med                      ...should return an error because of the missing <OUname>
check -wg -med                      ...should return an error because of the given but inappropriate <OUname>

Also I would like the user not having to care about the sequence as long as everything needed is there. This:

check -med -ou <OUname>             ...should work exactly as: 
check -ou <OUname> -med

Last, but not least I'd like to allow the user to do something like:

check -wg -ou <OUname1> <OUname2> -soft     ...Check all defined Workgroup-Machines and all machines in <OUname1> and <OUname2 >with relaxed settings.

Is there an intelligent way to parse the commandline parameters, something as a best practice? I'm cycling round this topic for days by now...for-next loops, switch-case, if-elseif...I can't find a solution that is easy to maintain/understand and functional likewise.

Can anybody of the pros here please hint me into the correct direction?

Best Regards,

Chris

Link to comment
Share on other sites

Have you reviewed the help file under Command Line Parameters? You could also search the forum for the many examples that use the $CmdLine built-in variable. It's not that complicated. Take a shot at parsing the $CmdLine array, and post some code to talk about if you get stuck.

:mellow:

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

I started this at lunch time thinking it would be simple. I was wrong.

Code

;---------------------------------
; CONSTANTS
;---------------------------------

Const $aLevels[3] = ["soft","med","hard"] ;Define global settings
Const $aTargets[3][2] = [["single",1],["wg",0],["ou",1]] ;Define global settings (1 = Additional arguments required, 0 = Boolean only)

;---------------------------------
; GLOBALS
;---------------------------------
Global $sCmd = $CmdLineRaw
Global $sCmd = '-wg -ou <OUname1> <OUname2> -soft' ;String for testing ONLY
Global $aErrors[1] = [0]

;---------------------------------
; DEFAULTS
;---------------------------------

$bCheckAll = True ;Check EVERYTHING by default, until overridden
$bCheckWorkgroup = False ;Do NOT scan workgroup by default

$sLevel = 'hard' ;Assign default level
$sCheckSingle = '' ;Skip single scan by default
$sCheckOU = '' ;Skip OU by default

;---------------------------------
; PREPARE ACTIONS
;---------------------------------

;Remove leading dash if it exists
If StringLeft($sCmd,1) = '-' Then $sCmd = StringTrimLeft($sCmd,1)

;Split command line arguments
$aArguments = _StringSplitRegExp($sCmd,'\s-')

;Loop through arguments
For $X = 1 to $aArguments[0]
    ;ConsoleWrite('[' & $X & ']: ' & $aArguments[$X] & @CRLF) ;DEBUG ONLY

    ;Assign argument
    $sArgument = $aArguments[$X]
    $sParameters = ''

    ;Attempt to split argument
    Local $aTemp = StringRegExp($sArgument,'^(.+?)(?:\s)(.*?)$',1)
    If Ubound($aTemp) Then
        $sArgument = $aTemp[0]
        $sParameters = $aTemp[1]
    EndIf

    ;ConsoleWrite("Argument: " & $sArgument & @CRLF)
    ;ConsoleWrite("Parameters: " & $sParameters & @CRLF)

    ;Look for target argument, return index if found
    $iIndex1 = InArray($aTargets,$sArgument)
    If NOT @ERROR Then
        ;See if additional parameters are required
        If $aTargets[$iIndex1][1] Then
            ;See if any parameters are present
            If $sParameters <> '' Then
                $bCheckAll = False ;Disable full check IMPORTANT!
                Switch $sArgument
                    ;Check a single system
                    Case 'single'
                        $sCheckSingle = $sParameters
                    ;Scan an organizational unit
                    Case 'ou'
                        $sCheckOU = $sParameters
                    Case Else
                        AddError("Argument not supported " & $sArgument)
                EndSwitch
            Else
                AddError("Additional parameters are required for argument: " & $sArgument)
            EndIf

        Else
            $bCheckAll = False ;Disable full check IMPORTANT!
            Switch $sArgument
                ;Check Workgroups (No options required)
                Case 'wg'
                    $bCheckWorkgroup = True
                Case Else
                    AddError("Argument not supported " & $sArgument)
            EndSwitch
        EndIf
    EndIf

    ;Look for level argument, return index if found (optional)
    $iIndex2 = InArray($aLevels,$sArgument)
    If NOT @ERROR Then
        $sLevel = $sArgument ;Modify scan level
    EndIf
Next

;---------------------------------
; PERFORM ACTIONS
;---------------------------------

;Check everything and stop
If $bCheckAll Then
    CheckAll()
    Exit
EndIf

;Check single (string) then stop
If $sCheckSingle <> '' Then
    CheckSingle()
    Exit
EndIf

;Check workgroups (boolean)
If $bCheckWorkgroup Then CheckWorkgroups()

;Check OU (string)
If $sCheckOU <> '' Then CheckOU()

;Dump any errors found
If $aErrors[0] Then
    ConsoleWrite('!' & $aErrors[0] & " ERROR(S) FOUND:" & @CRLF)
    For $X = 1 to $aErrors[0]
        ConsoleWrite('[' & $X & ']: ' & $aErrors[$X] & @CRLF)
    Next
EndIf

;---------------------------------
; CHECK FUNCTIONS
;---------------------------------

Func CheckAll()
    ConsoleWrite("Checking ALL systems (Level: " & $sLevel & ")" & @CRLF)
EndFunc

Func CheckSingle()
    ConsoleWrite("Checking single system (Level: " & $sLevel & "): " & $sCheckSingle & @CRLF)
EndFunc

Func CheckWorkgroups()
    ConsoleWrite("Checking workgroup (Level: " & $sLevel & ")" & @CRLF)
EndFunc

Func CheckOU()
    ConsoleWrite("Checking the following organizational units (Level: " & $sLevel & "):" & @CRLF)
    $aTemp = StringSplit($sCheckOU,' ')
    For $X = 1 to $aTemp[0]
        ConsoleWrite(@TAB & '[' & $X & ']: ' & $aTemp[$X] & @CRLF)
    Next
EndFunc

;---------------------------------
; COMMON FUNCTIONS
;---------------------------------

Func AddError($sMsg)
    Local $iCount = Ubound($aErrors)
    Redim $aErrors[$iCount+1]
    $aErrors[0] = $iCount
    $aErrors[$iCount] = $sMsg
EndFunc

;Look for string in an array
Func InArray($aArray, $sString)
    ; 1 dimensional array
    If Ubound($aArray,0) = 1 Then
        For $Y = 0 to Ubound($aArray)-1
            If $aArray[$Y] = $sString Then Return SetError(1,$Y,False)
        Next
        Return SetError(1,0,-1)
    ; 2 dimensional array
    ElseIf Ubound($aArray,0) = 2 Then
        For $Y = 0 to Ubound($aArray)-1
            If $aArray[$Y][0] = $sString Then
                ;ConsoleWrite("MATCH" & @CRLF)
                Return $Y
            EndIf
        Next
        Return SetError(1,0,-1)
    EndIf
EndFunc

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.0.0
 Author: WeaponX

 Script Function:
    Split string on regular expression

 Parameters:
    String = String to be split
    Pattern = Pattern to split on
    IncludeMatch = True / False - Indicates whether or not to include the match in the return (back-reference)
    Count = Number of splits to perform

#ce ----------------------------------------------------------------------------
Func _StringSplitRegExp($sString, $sPattern, $sIncludeMatch = false, $iCount = 0)

    ;All matches will be replaced with this string
    Local $sReservedPattern = Chr(0)
    ;Local $sReservedPattern = "#"
    Local $sReplacePattern = $sReservedPattern

    ;Modify the reserve pattern to include back-reference
    If $sIncludeMatch Then $sReplacePattern = "$0" & $sReplacePattern

    ;Replace all occurences of the search pattern with a replace string
    $sTemp = StringRegExpReplace($sString, $sPattern, $sReplacePattern, $iCount)

    ;Consolewrite($sTemp & @CRLF)

    ;Strip trailing character if it matches the reserved pattern
    If StringRight($sTemp, 1) = $sReservedPattern Then $sTemp = StringTrimRight($sTemp, 1)

    ;Split string using entire reserved string
    $aResult = StringSplit($sTemp, $sReservedPattern, 1)

    Return $aResult
EndFunc

Output

Checking workgroup (Level: hard)
Checking the following organizational units (Level: hard):
    [1]: <OUname1>
    [2]: <OUname2>
Edited by weaponx
Link to comment
Share on other sites

Have you reviewed the help file under Command Line Parameters? You could also search the forum for the many examples that use the $CmdLine built-in variable. It's not that complicated. Take a shot at parsing the $CmdLine array, and post some code to talk about if you get stuck.

:(

Yes I did. I always check the helpfile before posting here to save myself from replies stating "Hey, dumbo, look at the helpfile, check entries for $CmdLine". :mellow:

And no, you're not right: it IS that complicated.

But a.)

Command Line Parameters

The special array $CmdLine is initialized with the command line parameters passed in to your AutoIt script. Note the scriptname is not classed as a parameter; get this information with @ScriptName instead. A parameter that contains spaces must be surrounded by "double quotes". Compiled scripts accept command line parameters in the same way.

$CmdLine[0] is number of parameters

$CmdLine[1] is param 1 (after the script name)

$CmdLine[2] is param 2 etc

...

$CmdLine[$CmdLine[0]] is one way to get the last parameter...

...does this not contain any method or example how to work with more complex setups and b.) why should I reinvent the wheel? I'm quite sure that almost everyone of you has done something regarding commandline parameters...so please share.
Link to comment
Share on other sites

I started this at lunch time thinking it would be simple. I was wrong.

How long is your lunchtime break? :mellow:

I need some time to check your code - but I'll definitely get you feedback on it. Thanks so long!

Okay, back with 1st points: This is great! But the following commands are not processed correctly:

Global $sCmd = '-single Host -ou Group-1 Group-3 DC -soft' ;Checking single system (Level: hard): Host
Global $sCmd = 'wg -ou Group-1 Group-3 -med' ;Checking workgroup (Level: hard), Checking the following organizational units (Level: hard): Group-1, Group-3
Global $sCmd = '-wg -med' ;Checking workgroup (Level: hard)

Do you have a start for me?

EDIT: I removed the "NOT" from line 92 to get the correct check level.

Edited by cherdeg
Link to comment
Share on other sites

If it is a big amount of cmdline switches to handle then I opt for the abbreviations that i added to the full installed Scite4AutoIt3 editor. You have a choice of "cmdlineselect", "cmdlineselect2", "cmdlineswitch" and "cmdlineswitch2".

I will show by example how I typed "cmdlineswitch" (without quotes) into Scite4AutoIt3 and press the space bar to expand the abbreviation into the code structure that magically appears. Typed:

cmdlineswitch

pressed spacebar to get:

#region - CmdlineSwitch
If $CMDLINE[0] Then
    For $i = 1 To $CMDLINE[0]
        Switch $CMDLINE[$i]
            Case '/?'
                MsgBox(0x40000, @ScriptName & ' Help', _
                        'Switches are:' & @CRLF _
                         & @CRLF & '/extract' _
                         & @CRLF & @TAB & 'Extract files to current directory' _
                         & @CRLF & '/x' _
                         & @CRLF & @TAB & '' _
                         & @CRLF & '/x' _
                         & @CRLF & @TAB & '' _
                         & @CRLF & '/x' _
                         & @CRLF & @TAB & '' _
                         & @CRLF & '/x' _
                         & @CRLF & @TAB & '')
                Exit
            Case '/extract'
                FileInstall('?', @ScriptDir & '')
                Exit
            Case '/x'
            Case '/x'
            Case '/x'
            Case '/x'
            Case Else
                MsgBox(0x40000, 'Incorrect switch used', _
                        'Command used:' & @CRLF & $CMDLINERAW & @CRLF & _
                        @CRLF & 'Use /? for the switches available.')
                Exit
        EndSwitch
    Next
EndIf
#endregion

Now with some changes.

#cs - test switches to pass
    /hard /single singlehost        ; test1 ok
    /wg /ou host1,host2,host3       ; test2 ok
    /wg /ou /host1,host2,host3      ; test3 error
#ce

#region - CmdlineSwitch
Global $settings, $single, $wg, $ou
If $CMDLINE[0] Then
    For $i = 1 To $CMDLINE[0]
        Switch $CMDLINE[$i]
            Case '/?'
                MsgBox(0x40000, @ScriptName & ' Help', _
                        'Switches are:' & @CRLF _
                         & @CRLF & '/extract' _
                         & @CRLF & @TAB & 'Extract files to current directory' _
                         & @CRLF & '/soft' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/med' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/hard' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/single' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/wg' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/ou' _
                         & @CRLF & @TAB & 'Description')
                Exit
            Case '/extract'
                FileInstall('?', @ScriptDir & '\?')
                Exit
            Case '/soft'
                $settings = 1
            Case '/med'
                $settings = 2
            Case '/hard'
                $settings = 3
            Case '/single'
                $single = $CMDLINE[$i+1] ; assign next indexed value
                If StringLeft($single, 1) = '/' Then
                    ConsoleWriteError('Incorrect parameter following /single' & @CRLF)
                    Exit 1
                EndIf
                $i += $i ; increase $i
            Case '/wg'
                $wg = True
            Case '/ou'
                $ou = $CMDLINE[$i+1] ; assign next indexed value
                If StringLeft($ou, 1) = '/' Then
                    ConsoleWriteError('Incorrect parameter following /ou' & @CRLF)
                    Exit 1
                EndIf
                $i += $i ; increase $i
            Case Else
                MsgBox(0x40000, 'Incorrect switch used', _
                        'Command used:' & @CRLF & $CMDLINERAW & @CRLF & _
                        @CRLF & 'Use /? for the switches available.')
                Exit
        EndSwitch
    Next
EndIf
#endregion

; set hard settings by default if optin is not selected
If Not $settings Then
    $settings = 3
EndIf

; show variables for this test
MsgBox(0, @ScriptName, _
        '$settings = ' & $settings & @CRLF & _
        '$single = ' & $single & @CRLF & _
        '$wg = ' & $wg & @CRLF & _
        '$ou = ' & $ou _
        )

The example is not complete as Msgboxes for a CLI application is perhaps not suitable and error checking is incomplete etc. But it does show you that processing incoming cmdline switches can be achieved in an orderly fashion. Have a look at Jos' AutoIt3Wrapper source in the Scite4AutoIt3 install folder for a similar use of handling cmdline incoming switches. I have done projects that use many switches with the similar technique.

May I suggest that you use a comma separated list of hosts for the /ou switch and you can StringSplit them later in your script. And you may notice that I welcome the switches starting with a forward slash and not starting with a dash that is normally used in a posix based system.

Test in Scite4AutoIt3 with the commented switches in the script above or with your own combination. Just press Shift+F8 to show parameter window and add parameters to test with then press F5 to run the script.

Link to comment
Share on other sites

Something I wrote some time ago. It automatically recognizes the connection between a parameter and its value, so you logic for processing the parameters can be simpler. The complete commands of your script are stored in $CMDLINERAW. You can parse it with this function:

#include <Array.au3>
$CMDString = '/a:"value" -big="this -test:1\"23 is & $#@ _ your life" -test=th_3 -tte -äß$=/ätest/h.b'
$ResultArray = _ParseCMDLine($CMDString)
_ArrayDisplay($ResultArray)

;===============================================================================
;
; Function Name:   _ParseCMDLine($CMDString)
; Description::    Parses a CMD-String to Parameters with Values
; Parameter(s):    $CMDString -> String to parse
; Requirement(s):  ?
; Return Value(s): Error: 0 and @error = StringRegExp-Error 
;                  Success: 2 Dimensional Array: 
;                      $array[$i][0] : Parameter including value
;                      $array[$i][1] : Parameter 
;                      $array[$i][2] : Value with quotation marks (only if value has quotaion marks)
;                      $array[$i][3] : Value without quotation marks
; Author(s):       Prog@ndy
;
; Basis: http://regexlib.com/REDetails.aspx?regexp_id=1220
;===============================================================================
;
Func _ParseCMDLine($CMDString)
    Local $y, $j, $i, $entry
    Local $x = StringRegExp($CMDString,'(?:\s*)(?<=[-|/])(?<name>[^\s-|/:|=]*)(?:(?:[:|=](?:("(?<value1>.*?)(?<!\\)")|(?<value>\S*)))|\w*?)',4)
    If @error Then Return SetError(@error,0,0)
    Local $ResultArray[UBound($x)][4]
    For $i = 0 To UBound($x)-1
        $entry = $x[$i]
        For $y = 0 To UBound($entry)-1
            $j = $y
            If $y > 3 Then $j = 3
            $ResultArray[$i][$j] = $entry[$y]
        Next
    Next
    Return $ResultArray
EndFunc

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Link to comment
Share on other sites

Yes I did. I always check the helpfile before posting here to save myself from replies stating "Hey, dumbo, look at the helpfile, check entries for $CmdLine". :mellow:

It wasn't meant as any commentary on the powers of your AutoIt-Fu. :lol:

And no, you're not right: it IS that complicated.

Didn't seem so:
#cs
    check.exe                                       ...Checks all and everything with hardest settings
    check.exe [Options]                             ...Where Options are one or more of the following:
    
    [-Severity] [-Scope <Target>]
    
    Severity options:
    -soft                                   ...Checks selected target with relaxed settings
    -med, -medium                           ...Checks selected target with medium settings
    -hard  (default)                        ...Checks selected target with hardest settings
    
    Scope options:
    -*, -all  (default)                     ...Checks all and everything
    -single <Target>, -host <Target>        ...Checks the single host <Target> (Target host name is required)
    -wg, -wkgrp, -workgroup                 ...Checks all defined Workgroup-Machines
    -OU <Target>                            ...Checks all machines in the Target OUname (Target OU name is required)
#ce


Global $Severity = "HARD", $Scope = "ALL", $Target = ""
For $n = 1 To $CmdLine[0]
    Switch $CmdLine[$n]
        Case "-soft"
            $Severity = "SOFT"
        Case "-med", "-medium"
            $Severity = "MEDIUM"
        Case "-hard"
            $Severity = "HARD"
        Case "-all", "-*"
            $Scope = "ALL"
        Case "-host", "-single"
            $Scope = "SINGLE"
            $n += 1
            If Not _CheckTarget($n) Then Exit
        Case "-wg", "-wkgrp", "-workgroup"
            $Scope = "WORKGROUP"
        Case "-ou"
            $Scope = "OU"
            $n += 1
            If Not _CheckTarget($n) Then Exit
        Case Else
            MsgBox(16, "Parameter Error", "Invalid parameter in command line:  " & StringReplace($CmdLineRaw, $CmdLine[$n], " >>> " & $CmdLine[$n] & " <<< ", 1))
            Exit
    EndSwitch
Next
MsgBox(64, "Good Parameters", "$Severity = " & $Severity & @CRLF & _
        "$Scope = " & $Scope & @CRLF & _
        "$Target = " & $Target)


Func _CheckTarget($i)
    If $CmdLine[0] >= $i And $CmdLine[$i] <> "" And StringLeft($CmdLine[$i], 1) <> "-" Then
        $Target = $CmdLine[$i]
        Return 1
    Else
        MsgBox(16, "Parameter Error", "Missing required target parameter:  " & StringReplace($CmdLineRaw, $CmdLine[$i - 1], $CmdLine[$i - 1] & " >>> ??? <<< ", 1))
        Return 0
    EndIf
EndFunc   ;==>_CheckTarget

But a.)

...does this not contain any method or example how to work with more complex setups and b.) why should I reinvent the wheel? I'm quite sure that almost everyone of you has done something regarding commandline parameters...so please share.

I was suggesting checking the help file for the basics (which you may had already done) then using forum search to find many examples (which you hadn't).

:(

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

Hey guys: thank you all.

Finally I used Mhz's version; it does the best job as a sceleton for me and was far the easiest to understand and modify. And of course I needed to heavily modify it. Allover complexity didn't vanish also...just have a look:

; Includes
#include <Array.au3>

; Variables
Global $s_CRLF = @CRLF
Global $s_TAB = @TAB
Global $s_IniFile = "test.ini"
Global $a_IniOUsRaw
Global $a_IniOUs
Global $a_CmdLine = $CMDLINE ; a copy of the commandline parameters array
Global $s_CmdLineRaw = $CMDLINERAW ; a copy of the commandline parameters raw string
Global $s_CheckMode = "G1" ; the check mode: G1 (Group-1), G3 (Group-3) or G4 (Group-4). No parameter means G1
Global $s_Targets = "" ; the string of targets in SINGLE- or OU-Modes
Global $a_Execution[3] = ["AUTO", "G1", "WG"] ; the default for execution without commandline parameters


; Debug
$a_CmdLine = 0
;~ $s_CmdLine = "-g4 -ou OU-1 OU-2 OU-3 OU-4 OU-5 /workgroup"               ; ok
;~ $s_CmdLine = "-g1 -ou OU-1 OU-2 OU-3 OU-4 OU-5"                          ; ok
;~ $s_CmdLine = "-g3 -ou OU-1 OU-2 OU-3 OU-4 OU-5"                          ; ok
;~ $s_CmdLine = "-g1 /SINGLE host-1 host-2 host-3 -wg"                      ; ok
;~ $s_CmdLine = "-g4 /SINGLE host-1 host-2 host-3"                          ; ok
;~ $s_CmdLine = "-g1 /SINGLE host-1 host-2 host-3"                          ; ok
;~ $s_CmdLine = "-g1 -wg"                                                   ; ok
;~ $s_CmdLine = "-g4"                                                       ; ok
;~ $s_CmdLine = "-?"                                                        ; ok
$s_CmdLine = "--list"                                                       ; ok
$a_CmdLine = StringSplit($s_CmdLine, " ")
$s_CmdLineRaw = $s_CmdLine




; Main
_PrepareCommandline($a_CmdLine)
_ParseCommandline($a_Execution, $a_CmdLine)

ConsoleWrite($s_CRLF & "Result: " & $s_TAB &  $s_TAB & $a_Execution[0] & ", " & $a_Execution[1] & ", " & $a_Execution[2] & $s_CRLF) ; DEBUG


; Functions
Func _PrepareCommandline(ByRef $a_CmdLine)

    _ArrayDisplay($a_CmdLine) ; DEBUG

    If $a_CmdLine[0] > 1 Then
        $i_ArrayPosition = ""
        $s_TmpRecord = ""
        $a_TmpArray = $a_CmdLine
        For $i=$a_CmdLine[0] To 1 Step -1
            If Not (StringLeft($a_CmdLine[$i], 1) == "-" Or StringLeft($a_CmdLine[$i], 2) == "--" Or StringLeft($a_CmdLine[$i], 1) == "/") Then
                $s_TmpRecord &= $a_TmpArray[$i] & " "
                _ArrayDelete($a_TmpArray, $i)
                $a_TmpArray[0] = UBound($a_TmpArray)
            EndIf
        Next
        For $i_i=1 To $a_CmdLine[0]
            If ($a_CmdLine[$i_i] == "-ou" Or $a_CmdLine[$i_i] == "-Ou" Or $a_CmdLine[$i_i] == "-OU" Or $a_CmdLine[$i_i] == "--ou" Or $a_CmdLine[$i_i] == "/ou" Or $a_CmdLine[$i_i] == "/Ou" Or $a_CmdLine[$i_i] == "/OU") Then
                $i_ArrayPosition = $i_i
                _ArrayInsert($a_TmpArray, $i_ArrayPosition+1, $s_TmpRecord)
            EndIf
            If ($a_CmdLine[$i_i] == "-s" Or $a_CmdLine[$i_i] == "-S" Or $a_CmdLine[$i_i] == "-single" Or $a_CmdLine[$i_i] == "-Single" Or $a_CmdLine[$i_i] == "-SINGLE" Or $a_CmdLine[$i_i] == "--single" Or $a_CmdLine[$i_i] == "/s" Or $a_CmdLine[$i_i] == "/S" Or $a_CmdLine[$i_i] == "/single" Or $a_CmdLine[$i_i] == "/Single" Or $a_CmdLine[$i_i] == "/SINGLE") Then
                $i_ArrayPosition = $i_i
                _ArrayInsert($a_TmpArray, $i_ArrayPosition+1, $s_TmpRecord)
            EndIf
        Next
        $a_CmdLine = $a_TmpArray
    EndIf

EndFunc

Func _ParseCommandline(ByRef $a_Execution, $a_CmdLine)

    ConsoleWrite("Complete Command: " & $s_TAB & $s_CmdLineRaw & @CRLF) ; DEBUG
    _ArrayDisplay($a_CmdLine) ; DEBUG

    If $a_CmdLine[0] Then
        For $i_i = 1 To $a_CmdLine[0]
            ConsoleWrite("Found Parameter: " & $s_TAB & $a_CmdLine[$i_i] & @CRLF) ; DEBUG
            Switch $a_CmdLine[$i_i]
                Case "-wg", "-Wg", "-WG", "-workgroup", "-Workgroup", "-WORKGROUP", "--workgroup", "/wg", "/Wg", "/WG", "/workgroup", "/Workgroup", "/WORKGROUP"
                    If Not (StringInStr($s_CmdLineRaw, "-s") = 0 or StringInStr($s_CmdLineRaw, "-o") = 0  Or StringInStr($s_CmdLineRaw, "/s") = 0 or StringInStr($s_CmdLineRaw, "/o") = 0) Then $a_Execution[0] = "WG"
                Case "-s", "-S", "-single", "-Single", "-SINGLE", "--single", "/s", "/S", "/single", "/Single", "/SINGLE"
                    If Not (StringInStr($s_CmdLineRaw, "-w") = 0 Or StringInStr($s_CmdLineRaw, "/w") = 0) Then $a_Execution[2] = ""
                    $a_Execution[0] = "SINGLE"
                    $s_Targets = $a_CmdLine[$i_i+1]
                Case "-ou", "-Ou", "-OU", "--ou", "/ou", "/Ou", "/OU"
                    If Not (StringInStr($s_CmdLineRaw, "-w") = 0 Or StringInStr($s_CmdLineRaw, "/w") = 0) Then $a_Execution[2] = ""
                    $a_Execution[0] = "OU"
                    $s_Targets = $a_CmdLine[$i_i+1]
                Case "-g1", "-G1", "/g1", "/G1"
                    $a_Execution[1] = ""
                Case "-g3", "-G3", "/g3", "/G3"
                    $a_Execution[1] = "G3"
                Case "-g4", "-G4", "/g4", "/G4"
                    $a_Execution[1] = "G4"
                Case "-h", "-H", "-help", "-Help", "-HELP", "--help", "-?", "/h", "/H", "/help", "/Help", "/HELP", "/?"
                    ConsoleWrite($s_CRLF & "Result: " & $s_TAB &  $s_TAB & "My version runs Func _InputHelp() here" & $s_CRLF) ; DEBUG
                    Exit
                Case "-l", "-L", "-list", "-List", "-LIST", "--list", "/l", "/L", "/list", "/List", "/LIST"
                    ConsoleWrite($s_CRLF & "Result: " & $s_TAB &  $s_TAB & "My version runs Func _ListIniOUs() here" & $s_CRLF) ; DEBUG
                    Exit
                Case Else
                    If (StringLeft($a_CmdLine[$i_i], 1) == "-" Or StringLeft($a_CmdLine[$i_i], 2) == "--" Or StringLeft($a_CmdLine[$i_i], 1) == "/") Then
                        If $i_i == $a_CmdLine[0] Then
                            ConsoleWrite($s_CRLF & "Result: " & $s_TAB &  $s_TAB & "My version runs Func _InputError() here" & $s_CRLF) ; DEBUG
                            Exit
                        EndIf
                    EndIf
            EndSwitch
        Next
    EndIf

EndFunc

If anyone of you finds a way to strip the code down a little, it's highly appreciated! It would be cool to get rid of the StringInString and great to shorten the comparistons a bit.

Best Regards,

Chris

Edited by cherdeg
Link to comment
Share on other sites

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Link to comment
Share on other sites

  • 6 months later...

Something I wrote some time ago. It automatically recognizes the connection between a parameter and its value, so you logic for processing the parameters can be simpler. The complete commands of your script are stored in $CMDLINERAW. You can parse it with this function:

#include <Array.au3>
$CMDString = '/a:"value" -big="this -test:1\"23 is & $#@ _ your life" -test=th_3 -tte -äß$=/ätest/h.b'
$ResultArray = _ParseCMDLine($CMDString)
_ArrayDisplay($ResultArray)

;===============================================================================
;
; Function Name:   _ParseCMDLine($CMDString)
; Description::    Parses a CMD-String to Parameters with Values
; Parameter(s):    $CMDString -> String to parse
; Requirement(s):  ?
; Return Value(s): Error: 0 and @error = StringRegExp-Error 
;                  Success: 2 Dimensional Array: 
;                      $array[$i][0] : Parameter including value
;                      $array[$i][1] : Parameter 
;                      $array[$i][2] : Value with quotation marks (only if value has quotaion marks)
;                      $array[$i][3] : Value without quotation marks
; Author(s):       Prog@ndy
;
; Basis: http://regexlib.com/REDetails.aspx?regexp_id=1220
;===============================================================================
;
Func _ParseCMDLine($CMDString)
    Local $y, $j, $i, $entry
    Local $x = StringRegExp($CMDString,'(?:\s*)(?<=[-|/])(?<name>[^\s-|/:|=]*)(?:(?:[:|=](?:("(?<value1>.*?)(?<!\\)")|(?<value>\S*)))|\w*?)',4)
    If @error Then Return SetError(@error,0,0)
    Local $ResultArray[UBound($x)][4]
    For $i = 0 To UBound($x)-1
        $entry = $x[$i]
        For $y = 0 To UBound($entry)-1
            $j = $y
            If $y > 3 Then $j = 3
            $ResultArray[$i][$j] = $entry[$y]
        Next
    Next
    Return $ResultArray
EndFunc

Hi ProgAndy,

If the value ended with backslash character then the parsing is incorrect.

for examplae, use this $CmdLineRaw. Param1="c:\" Param2="C:\Program Files\SomeDir"

regards

Edited by lsakizada

Be Green Now or Never (BGNN)!

Link to comment
Share on other sites

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Link to comment
Share on other sites

  • 5 years later...
On 2/18/2010 at 0:45 AM, MHz said:

If it is a big amount of cmdline switches to handle then I opt for the abbreviations that i added to the full installed Scite4AutoIt3 editor. You have a choice of "cmdlineselect", "cmdlineselect2", "cmdlineswitch" and "cmdlineswitch2".

 

I will show by example how I typed "cmdlineswitch" (without quotes) into Scite4AutoIt3 and press the space bar to expand the abbreviation into the code structure that magically appears. Typed:

 

cmdlineswitch

pressed spacebar to get:

 

#region - CmdlineSwitch
If $CMDLINE[0] Then
    For $i = 1 To $CMDLINE[0]
        Switch $CMDLINE[$i]
            Case '/?'
                MsgBox(0x40000, @ScriptName & ' Help', _
                        'Switches are:' & @CRLF _
                         & @CRLF & '/extract' _
                         & @CRLF & @TAB & 'Extract files to current directory' _
                         & @CRLF & '/x' _
                         & @CRLF & @TAB & '' _
                         & @CRLF & '/x' _
                         & @CRLF & @TAB & '' _
                         & @CRLF & '/x' _
                         & @CRLF & @TAB & '' _
                         & @CRLF & '/x' _
                         & @CRLF & @TAB & '')
                Exit
            Case '/extract'
                FileInstall('?', @ScriptDir & '')
                Exit
            Case '/x'
            Case '/x'
            Case '/x'
            Case '/x'
            Case Else
                MsgBox(0x40000, 'Incorrect switch used', _
                        'Command used:' & @CRLF & $CMDLINERAW & @CRLF & _
                        @CRLF & 'Use /? for the switches available.')
                Exit
        EndSwitch
    Next
EndIf
#endregion

 

Now with some changes.

 

#cs - test switches to pass
    /hard /single singlehost        ; test1 ok
    /wg /ou host1,host2,host3       ; test2 ok
    /wg /ou /host1,host2,host3      ; test3 error
#ce

#region - CmdlineSwitch
Global $settings, $single, $wg, $ou
If $CMDLINE[0] Then
    For $i = 1 To $CMDLINE[0]
        Switch $CMDLINE[$i]
            Case '/?'
                MsgBox(0x40000, @ScriptName & ' Help', _
                        'Switches are:' & @CRLF _
                         & @CRLF & '/extract' _
                         & @CRLF & @TAB & 'Extract files to current directory' _
                         & @CRLF & '/soft' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/med' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/hard' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/single' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/wg' _
                         & @CRLF & @TAB & 'Description' _
                         & @CRLF & '/ou' _
                         & @CRLF & @TAB & 'Description')
                Exit
            Case '/extract'
                FileInstall('?', @ScriptDir & '\?')
                Exit
            Case '/soft'
                $settings = 1
            Case '/med'
                $settings = 2
            Case '/hard'
                $settings = 3
            Case '/single'
                $single = $CMDLINE[$i+1] ; assign next indexed value
                If StringLeft($single, 1) = '/' Then
                    ConsoleWriteError('Incorrect parameter following /single' & @CRLF)
                    Exit 1
                EndIf
                $i += $i ; increase $i
            Case '/wg'
                $wg = True
            Case '/ou'
                $ou = $CMDLINE[$i+1] ; assign next indexed value
                If StringLeft($ou, 1) = '/' Then
                    ConsoleWriteError('Incorrect parameter following /ou' & @CRLF)
                    Exit 1
                EndIf
                $i += $i ; increase $i
            Case Else
                MsgBox(0x40000, 'Incorrect switch used', _
                        'Command used:' & @CRLF & $CMDLINERAW & @CRLF & _
                        @CRLF & 'Use /? for the switches available.')
                Exit
        EndSwitch
    Next
EndIf
#endregion

; set hard settings by default if optin is not selected
If Not $settings Then
    $settings = 3
EndIf

; show variables for this test
MsgBox(0, @ScriptName, _
        '$settings = ' & $settings & @CRLF & _
        '$single = ' & $single & @CRLF & _
        '$wg = ' & $wg & @CRLF & _
        '$ou = ' & $ou _
        )

The example is not complete as Msgboxes for a CLI application is perhaps not suitable and error checking is incomplete etc. But it does show you that processing incoming cmdline switches can be achieved in an orderly fashion. Have a look at Jos' AutoIt3Wrapper source in the Scite4AutoIt3 install folder for a similar use of handling cmdline incoming switches. I have done projects that use many switches with the similar technique.

 

May I suggest that you use a comma separated list of hosts for the /ou switch and you can StringSplit them later in your script. And you may notice that I welcome the switches starting with a forward slash and not starting with a dash that is normally used in a posix based system.

 

Test in Scite4AutoIt3 with the commented switches in the script above or with your own combination. Just press Shift+F8 to show parameter window and add parameters to test with then press F5 to run the script.

 

I slightly modified MHz's first script on this page dated 18 Feb 2010 (quoted above) to parse command line arguments with defaults for omitted arguments...

#include <Date.au3>
 

;Declare variables and initialize defaults
Global $Mode = "MANUAL", $CurShift, $Shift, $LogFile=@YEAR & @MON & @MDAY & ".log"
Global $LogsFolder = @ScriptDir & '\Logs\', $LogFileName
Global $AMShiftStart = "07:30", $PMShiftStart = "15:30", $NIGHTShiftStart = "00:00"

GetLastCompletedShift(@HOUR & ":" & @MIN)    ;Get the last completed shift based on the current time
;GetLastCompletedShift("00:01")    ;Test with times set for different shifts
;GetLastCompletedShift("07:31")
;GetLastCompletedShift("15:31")
ConsoleWrite('$Mode: ' & $Mode & @CRLF & "$LogFile: " & $LogFile & @CRLF)
ConsoleWrite('$LogsFolder: ' & $LogsFolder & @CRLF & "$LogFileName: " & $LogFileName & @CRLF)
ConsoleWrite('$CurShift: ' & $CurShift & @CRLF & "$Shift: " & $Shift & @CRLF)

Local $Parms =  $CMDLINE, $Extended =  $CMDLINE, $pntr
ConsoleWrite("$Parms[0]" & $Parms[0] & " $Extended[0] " & $Extended[0] & @CRLF)
DoCmdLine()
AdjustLogDate()
$LogFileName = $LogsFolder & $LogFile
ConsoleWrite('$Mode: ' & $Mode & @CRLF & "$LogFile: " & $LogFile & @CRLF)
ConsoleWrite('$LogsFolder: ' & $LogsFolder & @CRLF & "$LogFileName: " & $LogFileName & @CRLF)
ConsoleWrite('$CurShift - ' & $CurShift & @CRLF & "$Shift " & $Shift & @CRLF)

;Do my other functions to load, parse, analyze and email logs here
Exit

Func DoCmdLine()
    If $CMDLINE[0] Then
        Local $Parms =  $CMDLINE, $Extended =  $CMDLINE, $pntr
        For $i = 1 To $CMDLINE[0]
            $Parms[$i] = StringRight($Parms[$i], StringLen($Parms[$i]) - 1)    ;strip off "/"
            $pntr = StringInStr($CMDLINE[$i], "=")
            If $pntr Then
                $Parms[$i] = StringLeft($CMDLINE[$i], $pntr - 1)
                $Extended[$i] = StringRight($CMDLINE[$i], StringLen($CMDLINE[$i]) - $pntr)
                $Parms[$i] = StringRight($Parms[$i], StringLen($Parms[$i]) - 1)    ;strip off "/"
            EndIf
            Switch StringUpper($Parms[$i])
                Case '?'
                    MsgBox(0x40000, @ScriptName & ' Help', _
                            'Command Line Switches are:' & @CRLF _
                             & @CRLF & '/AUTO|MANUAL' _
                             & @CRLF & @TAB & 'AUTO - Do all steps to complete and email summary automatically and exit' _
                             & @CRLF & @TAB & 'MANUAL - Do all steps to complete and email summary interactively' _
                             & @CRLF & @TAB & @TAB & 'default = manual' _
                             & @CRLF & '/AM|PM|NIGHT' _
                             & @CRLF & @TAB & 'Select one of three shifts (AM, PM or NIGHT)' _
                             & @CRLF & @TAB & @TAB & 'default = most recent shift completed' _
                             & @CRLF & '/LOGFILE=filename' _
                             & @CRLF & @TAB & 'Specify which log file to summarize (filename format - yyyymmdd.log)' _
                             & @CRLF & @TAB & @TAB & 'default = most recent log (Logs rotate at midnight)' _
                             & @CRLF & '/LOGSFOLDER=path' _
                             & @CRLF & @TAB & 'Select the logs folder path to use' _
                             & @CRLF & @TAB & @TAB & 'default = ' & $LogsFolder _
                             & @CRLF & @CRLF & 'Example = ' & @ScriptName & " /auto /pm /Logfile=20160616.log /logsfolder=C:\NurseCallMon\Logs\")
                    Exit
                Case 'AUTO', 'MANUAL'
                    $Mode = StringUpper($Parms[$i])
                Case 'AM', 'PM', 'NIGHT'
                    $Shift = StringUpper($Parms[$i])
                Case 'LOGFILE'
                    $LogFile = $Extended[$i]
                Case 'LOGSFOLDER'
                    $LogsFolder = $Extended[$i]
                    if StringRight($LogsFolder,1)<> "\" Then $LogsFolder = $LogsFolder & "\"
                Case Else
ConsoleWrite('$Parms[$i] ' & $Parms[$i] & @CRLF & "$Extended[$i] " & $Extended[$i] & @CRLF)
                    MsgBox(0x40000, 'Incorrect switch used', _
                            'Command used:' & @CRLF & $CMDLINERAW & @CRLF & _
                            @CRLF & 'Use /? for the switches available.')
                    Exit
            EndSwitch
        Next
    EndIf
EndFunc

Func GetLastCompletedShift($tTime)
    ;Detect the shift from the current time to find last completed shift
    $CurShift = "NIGHT"    ;set Defaults before time tests below
    $Shift = "PM"
    If $tTime >= $AMShiftStart Then
        ;Bump it if after the start of the AM shift
        $CurShift = "AM"
        $Shift = "NIGHT"
    EndIf
    If $tTime >= $PMShiftStart Then
        ;Bump it if after the start of the AM & PM shifts
        $CurShift = "PM"
        $Shift = "AM"
    EndIf

EndFunc

Func AdjustLogDate()
    ;If NIGHT shift is requested then get the previous days log file since logs are rotated at Midnight
    local     $sNewDate
    If $Shift = "NIGHT" And $LogFile = @YEAR & @MON & @MDAY & ".log" then
        $LogFile = @YEAR & @MON & @MDAY-1 & ".log"
        $sNewDate = _DateAdd('d', -1, _NowCalcDate())
        $sNewDate = StringLeft($sNewDate,4) & StringMid($sNewDate,6,2) & StringRight($sNewDate,2)
        $LogFile = $sNewDate & ".log"
    EndIf
ConsoleWrite(@ScriptLineNumber & ' $CurShift: ' & $CurShift & @CRLF & "$Shift: " & $Shift & @CRLF & @YEAR & @MON & @MDAY & @CRLF & $sNewDate & @CRLF)

EndFunc

 

Link to comment
Share on other sites

  • 3 years later...

Considering there is demand for this I wrote this basic parser in a pinch.

Paste into a text file named Parameter.au3 then include it atop your script.

_GetParameter(String Parameter Name, Optional default value if not found, type bool or string)

The default value, if omitted will be an empty string for string types (default) or false for bool types.

I added the bool type notion to check for just the existence of a parameter without any specific value as the next $CmdLine, like for example /help or /force etc... The default, string type, will return the next $CmdLine item as such, unless there is nothing behind your parameter in which case it returns the default value as well (empty string).

Example usage:

If _GetParameter("help", false, "BOOL") Then
; show some help with MsgBox or something like that
EndIf

$myUser = _GetParameter("user", "NoBody")
If $myUser = "NoBody" Then
; handle if no username was provided, like messaging the /user option is mandatory
EndIf


 

#include <Array.au3>

; Parameter name should not be prefixed with / or - as we will add this ourself in the search
; Type should be string or bool
; String will return the next $CmdLine value whereas bool will return True or False whether the parameter is found or not
; Default should be the default value in case the option is not given

Func _GetParameter($name, $default = Default, $type = "STRING")
    $uType = StringUpper($type) ; I know = is case insensitive, but just in case...
    
    ; if there is no default specified then initialize the $default var according to the type
    If $default = Default then
        if $type = "STRING" then
            $default = ""
        else
            $default = false
        endif
    EndIf
    
        ; First make sure there were command line arguments given else we return the default
    If $CmdLine[0] = 0 Then
        Return $default
    EndIf

    ; Just in case the dev' uses / or - let's test for that
    If StringLeft($name, 1) == "-" or StringLeft($name, 1) == "/" Then
        ; Only search as requested, no variations
        $i = _ArraySearch($CmdLine, $name)

        If $type = "STRING" and $i > 0 and $i < $CmdLine[0] Then
            Return $CmdLine[$i + 1]
        ElseIf $type = "BOOL" and $i > 0 Then
            Return True
        Else
            Return $default
        EndIf

    Else
        ; Search with / in front of parameter name (Microsoft default)
        $i = _ArraySearch($CmdLine, "/" & $name)
        
        ; If not found try again with - in front of name
        If $i = -1 Then
            $i = _ArraySearch($CmdLine, "-" & $name)
        EndIf

        If $type = "STRING" and $i > 0 and $i < $CmdLine[0] Then
            Return $CmdLine[$i + 1]
        ElseIf $type = "BOOL" and $i > 0 Then
            Return True
        Else
            Return $default
        EndIf
                
    EndIf
        
EndFunc

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...