Flexible Parameterübergabe (Konsole)

  • Hallo !
    Ich brauche mal wieder einen Schubs :D

    Ich schreibe gerade ein Script, welches mir die täglichen AdminChecks bestimmter Dateien und Attribute abnehmen soll.
    (Kommandozeilenprogramm)

    Jetzt wollte ich bei der Gelegenheit die Parameterübergabe beim Aufruf etwas flexibler als mit $Cmdline[ ] gestalten.
    Das ist mir zu Statisch, da bei bestimmten Schaltern zusätlich Schalter gefordert werden und bei anderen nicht. Das wäre mit $Cmdline[] zu viel
    frickelarbeit.

    Des hab ich mal versucht:

    Spoiler anzeigen
    [autoit]


    $line=$CmdLineRaw
    $string=StringSplit($line,"-")
    For $i=0 to $string[0] Step 1
    $params=StringSplit($string[$i+2], " ")
    $parameter[$i][0]=$params[1]
    $parameter[$i][1]=$params[2]
    Next

    [/autoit]

    Aufruf ist z.B folgender:
    fileop datei.txt -S Suchstring -m .....
    Habe mir also erstmal die ganze Eingabezeile in die Variable $line geholt.
    StringSplit "-"
    Erzeugt auf jeden Fall schon mal die jeweiligen Paare d.h
    in $string[2] steht dann "S suchstring"
    Jetzt wollte ich mit einem erneuten StringSplit " " dafür sorgen, dass
    "S suchstring" auch von einander getrennt werden. Und das Resultat in das Zweidimensionale Array $parameter packen. So das ich immer zu dem Schalter auch die übergebenen Parameter abspeichere.

    Leider bekomme ich beim Ausführen des Skriptes immer folgende Fehlermeldung:
    $parameter[$i][0]=$params[1]
    ^Error: Badly formated variable or macro

    Ich wüsste nicht, was daran "Badly formated" sein soll.

    Was mach ich falsch ????

    Gruß
    Gawe

    • Offizieller Beitrag

    Zwei Probleme:

    [autoit]

    $parameter[$i][0]

    [/autoit]

    ==> dieses Array ist gar nicht deklariert, daher der Fehler
    Aber auch wenn du es deklarierst:

    [autoit]

    $string=StringSplit($line,"-")
    Dim $parameter[$string[0]][2]

    [/autoit]

    führt die Codezeile:

    [autoit]

    $params=StringSplit($string[$i+2], " ")

    [/autoit]

    zu einem neuen Fehler, da mit $i+2 der Bereich überschritten wird.

    Tipp: Verwende zum selektieren StringRegExp().

    • Offizieller Beitrag

    Na, schon weiter gekommen? ;)

    Hier mal eine Lösung von mir:

    Spoiler anzeigen
    [autoit]

    #include <array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Dim $arParameter[1][2]
    Dim $line = 'fileop datei.txt -S Suchstring -m BlaBla'
    $parameter = StringRegExp($line, '((?<=\s-)\w\s\w+((?=\s-)|(?!.)))', 3)
    For $i = 0 To UBound($parameter)-1
    If $parameter[$i] <> '' Then
    $param = StringSplit($parameter[$i], ' ')
    If $arParameter[0][0] = '' Then
    $arParameter[0][0] = $param[1]
    $arParameter[0][1] = $param[2]
    Else
    ReDim $arParameter[UBound($arParameter)+1][2]
    $arParameter[UBound($arParameter)-1][0] = $param[1]
    $arParameter[UBound($arParameter)-1][1] = $param[2]
    EndIf
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _ArrayDisplay($arParameter, 'Parameterliste')

    [/autoit]


    Erläuterung zum RegExp - Pattern:

    Code
    (?<=\s-)	prüfe ob VOR dem Match (?<=) ein Leerzeichen gefolgt von einem - steht (\s-)
    \w		jetzt muß ein Zeichen vom Typ 'Word Character' folgen
    \s		darauf muß ein Leerzeichen folgen
    \w+		jetzt können beliebig viele Zeichen vom Typ 'Word Character' folgen
    ((?=\s-)|(?!.))	| bedeutet ODER, Bedingung links oder rechts der Pipe muß zutreffen
    (?=\s-)		prüfe ob NACH dem Match (?=) ein Leerzeichen gefolgt von einem - steht (\s-)	ODER
    (?!.)		prüfe ob NACH dem Match (?) KEIN Zeichen folgt: (!) = Verneinung, (.) = beliebiges Zeichen
  • Ähm...
    Ich sag schon mal artig Danke. :D
    Aber du verwendest da jetzt ein paar Sachen, die muss ich mir jetzt erstmal auf der Zunge zergehen lassen :hammer:

    Gruß
    Gawe

  • Sorry mir war grad langweilig.
    So sollte es auch gehen:


    Spoiler anzeigen
    [autoit]

    #include <array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $CMDLineRaw = 'fileop datei.txt -S Suchstring -m BlaBla'
    $r = StringRegExp($CMDLineRaw, '-(\w) ([\w\.]+)', 3)
    If IsArray($r) Then
    Dim $P[UBound($r)/2][2]
    For $i = 0 To UBound($r)-1
    $P[$i/2][Mod($i,2)] = $r[$i]
    Next
    _ArrayDisplay($P, 'Parameterliste')
    EndIf

    [/autoit]

    Einmal editiert, zuletzt von AspirinJunkie (9. August 2007 um 12:02)

  • Musst dich doch nicht entschludigen.
    Ich hoffe mir ist auch irgendwann mal so langweilig. ;)

    Sieht auf jeden Fall sehr kompakt aus.
    Ich muss mich erstmal mit Regex beschäftigen.
    Im Augenblick habe ich noch Schwierigkeiten alles zu interpretieren.

    Gruß
    Gawe

  • Ne is ja klar - reguläre Ausdrücke lernt man nicht mal so in paar Stunden.
    Das schöne daran aber ist das es nicht auf AutoIt begrenzt ist sondern fast überall vorkommt.
    Deswegen gibt es viel Material dazu.

    Empfehle dir z.B. >>dieses Tutorial<<.


    Wenn ich das schon poste sollte ich es auch erklären.
    Also gut fangen wir an:

    Die erste Zeile sollte klar sein.
    Danach splitten wir unseren Parameterstring mittels RegExp.
    Hier die Erklärung zu meinem Pattern:

    Code
    '-(\w) ([\w\.]+)'

    Ein Bindestrich gefolgt von einem Buchstaben ( \w ).
    Der Buchstabe wird in Klammern gesetzt weil er damit einzeln ausgegeben wird.
    Dann kommt ein Leerzeichen und eine Reihe von Buchstaben oder (das in eckigen Klammern bedeutet "oder") Punkten ( \. ) mit einer Mindestlänge von einem Zeichen ( + ).
    Das zweite wird ebenfalls wieder in Klammern gesetzt damit es dann gesondert ausgeben wird.

    Was wir nun erhalten ist das Array $r welches folgende Elemente enthält:

    Spoiler anzeigen
    Code
    [0] S
    [1] Suchstring
    [2] m
    [3] BlaBla

    Man erkennt also das die Bindestrich-Parameter einen geraden Index haben und ihr zugehöriger Spezifizierungsparameter einen Index weiter folgt (also ein ungerader Index).

    Mit "If IsArray($r) Then" prüfen wir lediglich ob überhaupt was gefunden wurde da es sonst einen Fehler geben würde.
    Nun können wir unser 2-Dim Array $P erstellen welches später die Parameter in gewünschter Form aufnehmen soll.
    Da wissen wir ja nun das es insgesamt halb so viele Elemente geben soll wie Elemente in $r vorhanden sind (da dort für einen Eintrag ja je 2 Index belegt sind).
    Deswegen deklarieren wir unser Array $P so:

    Dim $P[UBound($r)/2][2]

    Das heißt das die Länge der ersten Dimension halb so viele Elemente umfassen soll wie Elemente in $r vorhanden sind ( UBound($r) ).
    Die [2] für die 2. Dimension ist denke ich klar.

    Nun wird unser Array $r komplett durchlaufen:

    For $i = 0 To UBound($r)-1

    $i enthält dann immer den jeweiligen Index des Elementes von $r bei welchem wir uns aktuell befinden.

    Nun zur gemeinsten Zeile ;):

    [autoit]

    $P[$i/2][Mod($i,2)] = $r[$i]

    [/autoit]

    Dies bedeutet:

    Schreibe unser Ausgabearray $P.
    Da wir ja sagten das es nur halb so viele Elemente wie in $r gibt können wir die erste Dimension mit [$i / 2] festlegen - warum?:

    $i gibt den aktuellen Index von $r an.
    Wäre $i gerade z.B. [2] dann wären wir beim Bindestrich-Parameter des eigentlich 2. Gesamtparameters.
    Also wollen wir es in unser Ausgabearray $P an die 2. Position in der ersten Dimension haben.
    Teilen wir [2] durch 2 erhalten wir "1" - also die 2. Stelle in unserem neuen Array (da "0" ja die erste Stelle ist).
    Gehen wir nun weiter und erhöhen $i um 1 auf nun [3] haben wir nun den Spezialisierungsparameter des 2. Gesamtparameters.
    Teilen wir hier nun $i durch 2 erhalten wir "1.5".
    Da als Index aber nur Ganzzahlen zugelassen sind wird intern einfach die ".5" abgeschnitten - wir haben also nun wieder "1" - also wieder die 2. Stelle in unserem Ausgabearray.

    Nun müssen wir das Element in die richtige Position in der 2. Dimension bringen.

    Dafür ist Mod($i,2) zuständig.
    Diese Funktion prüft $i auf die Teilbarkeit durch 2.
    Ist es ohne Rest teilbar - also eine gerade Zahl (und damit unsere Bindestrich-Parameter) erhalten wir als Ausgabewert der Funktion eine "0" - und damit unseren gewünschten Index der 2. Position.
    Ist die Zahl ungerade erhalten wir "1" - und damit den anderen Index.

    Ich hoffe mal das hat dich bisschen weiter gebracht erstmal.

  • Spitze !

    Danke für die Super Erklärung. :D

    Ich setze mich heut abend nochmal ran.

    Gruß
    Gawe

  • Naja hat ein bischen gedauert. Urlaub :D
    Irgendwie haben die Pattern nicht gefunzt.
    Aufruf soll ja z.B sein:

    filecheck -f datei.txt -S Suchstring -stsd Test -savsts -m

    Ich hab mir jetzt mal folgendes Pattern gebaut:

    [autoit]

    \-(\S+)\s([^\-]\S+)

    [/autoit]


    Das filtert mir jetzt alle Schalter heraus zu denen auch Parameter ausgegeben werden. Auch wenn die Schalter aus mehr wie einem Buchstaben bestehen.

    Mein Problem ist jetzt, die Schalter ohne Parameter herauszufiltern.
    In meinem ersten Aufruf will ich die nicht haben, da die sonst das System mit
    Array geraden Index = Schalter
    Array ungeraden Index = Parameter
    durcheinanderwürfeln würden.

    Also bin ich am Basteln eines Pattern das nur die Schalter herausfiltert die mit einem "-" anfangen, aus einem oder meheren Buchstaben bestehen und wo danach entweder ein Leerzeichen und ein weiteres "-" auftaucht ODER eben garnichts (siehe Schalter -m)

    Mir macht jetzt die definition eines ODER Schwierigkeiten. Der Rest wäre an sich kein Problem, nur ziehen meine Definitionen immer beim letzten Schalter nicht. Weil da ja kein Leerzeichen mehr kommt, sondern eben NICHTS. Nur was ist dieses NICHTS ? (Wortgrenze \b funktioniert auch nicht)

    Gruß
    Gawe

  • Hallo !
    Also z.B

    [autoit]

    \-(\S+)\s\-|.....

    [/autoit]

    Die Syntax ist jetzt hinter dem letzten Minus nicht mehr in Ordnung, nicht wundern. Da liegt nämlich der Knackpunkt bei dem ich nicht weiß wie es weitergeht.

    Mit dem Pattern wird z.B der Schalter -savsts (siehe vorherigen Post) richtig erkannt.

    Ich versuche mal im Pseudocode nocheinmal darzustellen was ich möchte:

    Suche alles was mit einem Minus beginnt
    Nach dem Minus und beliebig vielen Zeichen kommt entweder
    ein Leerzeichen und ein weiteres Minus
    ODER
    Nichts mehr (<- Was ist dieses nichts ?)

    Wenn ich die Befehlzeile eingebe, kommt ja nach -m nichts mehr, daher kriege ich es mit meinem Pattern nicht gegriffen.

    Gruß
    Gawe

  • Ich glaub jetzt hab ich's.
    Manchmal ist man wie vernagelt.

    Da das ganze ja nur einmal in jeder Zeile vorkommen kann und zwar nur am Ende der Zeile , hab ich mir überlegt ich zäume das Pferd auch von hinten auf.

    [autoit]

    \-(\S+)$

    [/autoit]

    Scheint mir der Druchbruch zu sein.

    Trotzdem Danke !


    Gruß
    Gawe

    • Offizieller Beitrag

    Hi,

    ich hatte es so gedacht:

    [autoit]

    #include<array.au3>
    Global $allesNacheinander = '-\w+|[0-9_\w\.]+'
    Global $nurParameter = '-\w+'
    Global $str = '-f datei.txt -S Suchstring -stsd Test -savsts -m'

    [/autoit][autoit][/autoit][autoit]

    $re = StringRegExp($str, $allesNacheinander, 3)
    _ArrayDisplay($re)

    [/autoit][autoit][/autoit][autoit]

    $re = StringRegExp($str, $nurParameter, 3)
    _ArrayDisplay($re)

    [/autoit]

    So long,

    Mega

  • Hallo !
    Erstmal danke für deine Bemühungen:

    Hab dein Pattern mal getestet.
    Problem ist dabei der haut alles in ein Array. (Kann auch sein das wir uns da mißverstanden haben, ich will alle Schalter die kein Parameter bekommen haben in einem Array haben, da die Schalter die ein Parameter bekommen haben bereits in einem anderen Array gespeichert sind, wo ich sie mir sauber wieder rausziehen kann, da ein gerader Index immer ein Schalter ist und ein ungerader immer der dazugehörige Parameter.)

    Sonst wird es dann schwer herauszufinden welcher Parameter zu welchem Schalter gehört. Da sich jetzt auch die Schalter die kein Parameter benötigen und auch der Dateiname des Skriptes in dem Array befinden.

    Allerdings ist meine Lösung auch nicht der Weisheit letzter Schluss, denn beid er momentanden Konstellationen muss ich auf die Kommandozeile 3 Abfragen laufen lassen:
    das erste Array enthält dann alle Schalter mit optionen
    Die Zweite Abfrage würde mir alle Schalter ohne Optionen außer den letzten Schalter liefern.
    Und dann muss noch eine Abfrage laufen mit dem Regex von eben, damit ich prüfe ob am Zeilenende noch ein Schalter ohne Parameter existiert.

    Ich werde es erstmal so einbauen, aber glücklich bin ich nicht damit.

    Gruß
    Gawe

    • Offizieller Beitrag

    HI,

    [autoit]

    #include<array.au3>
    Global $allesNacheinander = '-\w+|[0-9_\w\.]+'
    Global $nurParameter = '-\w+'
    Global $nurParameterOhneZusatz = '-\w+(?! \w|\w)'
    Global $str = '-f datei.txt -q -S Suchstring -stsd Test -savsts -m'

    [/autoit][autoit][/autoit][autoit]

    $re = StringRegExp($str, $allesNacheinander, 3)
    ;_ArrayDisplay($re, 'Alles')

    [/autoit][autoit][/autoit][autoit]

    $re = StringRegExp($str, $nurParameter, 3)
    ;_ArrayDisplay($re, 'nur Parameter')

    [/autoit][autoit][/autoit][autoit]

    $re = StringRegExp($str, $nurParameterOhneZusatz, 3)
    _ArrayDisplay($re, '$nurParameterOhneZusatz')

    [/autoit]

    So long,

    Mega

  • Super !
    Aber kannst du mir den Regex bitte erläutern:

    [autoit]

    -(\w+(?!\w|\w)

    [/autoit]

    Fängt mit Minus an,
    dann folgen beliebig viele Zeichen
    - dann kommt wohl ein negatives Lookahead !?
    das kein Zeichen folgt
    oder ein Zeichen ?(


    Gruß
    Gawe