Kommandozeilen parsen ( _CmdLine_Parse )

    • Offizieller Beitrag

    Kommandozeilen sind immer gleich aufgebaut:

    Teil_1: eine ausführbare Datei mit/ohne Pfad

    Teil_2: Parameter 1

    ...

    Teil_n: Parameter n -1

    Im Normalfall sollten Pfade so angegeben werden, dass sie bei enthaltenen Leerzeichen in Stringbegrenzer gekapselt werden. Leider halten sich nicht alle Funktionen daran (Registry Einträge).

    Deshalb habe ich diese Funktion erstellt, die bei nicht vorhandenen Stringbegrenzern nach der ersten angegebenen ausführbaren Datei sucht und damit den Pfad für diese Datei abschließt.

    Alle anderen Parameter sind durch Leerzeichen getrennt.

    Python: Bsp.
    #include 'CmdLineParse.au3'
    
    Local $sCmd = 'C:\Program Files\Intel\bin\iWrap.exe /CMD:7 %1'
    Local $aRes = _CmdLine_Parse($sCmd)
    For $i = 0 To UBound($aRes) -1
        ConsoleWrite($aRes[$i] & @CRLF)
    Next

    EDIT:

    Kleine formelle Änderung im Skript. Ich hatte nicht auf dem Schirm, dass AutoIt in RegEx-Funktionen das insensitiv Flag hat '(?i)'. Hatte daher die Lua-Variante: '[upper lower]' gebastelt.

    Hier im Text geändert, nicht im Anhang - bitte selbst anpassen bei Bedarf (funktionell nicht erforderlich).

  • Was hältst du denn hiervon:

  • Was hältst du denn hiervon :

    Enthält der zu parsende String z.B. einen Parameter mit Leerzeichen (trotz 'quotes'), also z.B. :

    'C:\Program Files\Intel\bin\iWrap.exe "C:\Test Dir\" %1'

    dann wird das bei Deinem Ansatz nicht berücksichtigt - bei BugFix schon !

    Bitnugger :

    C:\Program Files\Intel\bin\iWrap.exe

    C:\Test Dir" %1

    BugFix :

    C:\Program Files\Intel\bin\iWrap.exe

    "C:\Test Dir\"

    %1

    Edit : Problem bei "C:\Test Dir\" ist der finale Backslash nicht das Leerzeichen - siehe Beitrag #5

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    Einmal editiert, zuletzt von Musashi (18. Juli 2019 um 06:20)

  • Siehe : _WinAPI_CommandLineToArgv !

    Aus 'C:\Program Files\Intel\bin\iWrap.exe "C:\Test Dir\" %1' wird :

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    Einmal editiert, zuletzt von Musashi (18. Juli 2019 um 06:24)

  • Weitere Ergänzung :

    Da _WinAPI_CommandLineToArgv ja CommandLineToArgvW aus der shell32.dll aufruft, habe ich mir das in der MSDN Library mal kurz angesehen.

    Auszug :

    CommandLineToArgvW hat eine spezielle Interpretation von Backslash-Zeichen, wenn ihnen ein Anführungszeichen (") folgt. Diese Interpretation geht davon aus, dass jedes vorhergehende Argument ein gültiger Dateisystempfad ist, oder es kann sich unvorhersehbar verhalten.

    Diese 'spezielle' Interpretation führt dazu, dass aus :

    'Parameter1 "Ich bin ein Backslash" %1'

    Parameter1  

    Ich bin ein Backslash  

    %1

    wird, aus :

    'Parameter1 "Ich bin ein \" %1' aber

    Parameter1  

    Ich bin ein " %1

    ( Bitnugger : Darum auch das Problem mit dem Parameter "C:\Test Dir\" )

    Das mag ja alles einen tieferen Sinn haben, der sich mir allerdings nicht erschließt :whistling:.

    Ich möchte einen quoted String wie "Sonderzeichen des Tages ist der \" verwenden können, ohne dass 'spezielle' Interpreten vor sich hin interpretieren :P.

    Im Verlauf der MSDN-Info wird zwar noch näher auf die Parserlogik von CommandLineToArgvW eingegangen, aber das ist mir jetzt schon zu spät :sleeping:.

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    • Offizieller Beitrag

    Ich habe hier ganz bewusst ausschließlich String-Funktionen verwendet, weil die API-Funktionen allesamt keine Abweichung vom Idealfall zulassen. Steht auch in den jeweiligen Remarks immer erwähnt, dass den Funktionen eigentlich grundsätzlich nicht zu vertrauen ist und man sie nur anwenden soll, wenn sicher ist, dass der auszuwertende String zu 100% den (viel zu engen) Anforderungen der Funktion entspricht. [Das ist jetzt meine etwas überspitzte Interpretation der Remarks]

    Natürlich ist es korrekt zu sagen: Das kann die Funktion, aber nur bei den und den Bedingungen. Mir war aber das Korsett zu eng. Mir ist es lieber, dass eine Funktion auch evtl. abartige Sonderfälle behandelt. Dann ist diese Behandlung einmalig integriert und muss nicht immer wieder, wenn Sonderfälle auftreten könnten, in die Nachbehandlung eingebunden werden.

  • Ich habe hier ganz bewusst ausschließlich String-Funktionen verwendet, weil die API-Funktionen allesamt keine Abweichung vom Idealfall zulassen.

    Ja, in der Tat. Das hat Musashi mit seinem Bsp. ja sehr gut verdeutlicht.

    Zwei Dinge an deinem Script würde ich aber noch ein wenig ändern.

    1.) Local $aExec[] = ['.exe','.com','.bat','.cmd','.scr']

    Hier solltest du besser die Umgebungsvariable PATHEXT auswerten.

    Local $aExec = StringSplit(EnvGet('PATHEXT'), ';', 2) ; Hehe, ist ja lustig... denn so funktioniert es nicht! --> Local $aExec[] = StringSplit(EnvGet('PATHEXT'), ';', 2)

    2.) Local $iMatch, $iPos = 1024, $sExt = ''

    Wenn ich es recht verstehe, gibst du mit $iPos die maximale Länge einer Befehlszeile vor. Die darf aber unter Windows XP und höher 8191 Zeichen und unter Windows 2000 oder Windows NT 4.0 2047 Zeichen lang sein.

    Local $iMatch, $iPos = @OSType = 'WIN32_NT' ? 8191 : 2047, $sExt = ''

    • Offizieller Beitrag

    zu 1.

    Die Variante hatte ich zuerst. Da ".scr" nicht angegeben wird (ein gern genutztes Einfallstor für Schadcode) habe ich mich auf eine Liste der selbst ausführbaren Dateien beschränkt und die, die einen Interpreter erfordern aussen vor gelassen. - Könnte man aber auch kombinieren.

    zu 2.

    Die Längenangabe war willkürlich, die genaue Angabe für MAXPATH wollte ich noch nachschauen - verpennt.