Reguläre Ausdrücke (RegEx) in PowerShell verwenden

    Reguläre Ausdrücke in PowerShellDie Unterstützung für reguläre Ausdrücke gehört zum Pflichtprogramm für eine moderne Script-Sprache. PowerShell bietet mehrere Sprach­kon­strukte, die eine Verwendung von RegEx zu­lassen. Bei der syntaktischen Umsetzung orien­tierte sich Microsoft - anders als etwa bei Word - weitgehend an Perl, so dass für die meisten RegEx-erfahrenen Anwender der Lernaufwand gering bleibt.

    Im Vergleich zu einfachen Wildcards sind reguläre Ausdrücke viel mächtiger, weil sich ihre Möglichkeiten nicht auf Substrings und simple Platzhalter reduzieren. Beispielsweise lassen sich damit Bereiche festlegen (z.B. [a-d]), Typen von Zeichen (numerisch, alphabetisch, Whitespace, etc.) unterscheiden oder die Häufigkeit ihres Vorkommens durch verschiedene Quantifizierer beliebig bestimmen. Besonders praktisch beim Suchen und Ersetzen ist die Möglichkeit, die beim Matching ermittelten Fundstellen als Variablen im Ersetzungstext nutzen zu können. Eine gute Übersicht über die sprachlichen Mittel von RegEx in PowerShell gibt dieses Cheat Sheet (PDF).

    Mustervergleich mit dem Operator -match

    PowerShell bietet eine Reihe von Vergleichsoperatoren, die sich nicht nur auf numerische Werte anwenden lassen, sondern auch auf String-Objekte. Einer davon ist -match, dessen Besonderheit darin besteht, dass er als Vergleichsausdruck nicht nur wörtlich zu nehmende Zeichenketten akzeptiert, sondern auch RegEx:

    "Reguläre Ausdrücke in PowerShell 3.0" -match "shell\s*(\d)"

    Dieser Ausdruck ergibt den Wert TRUE. Das ist insofern überraschend, als bei RegEx normalerweise zwischen Groß- und Kleinschreibung unterschieden wird. Im obigen Beispiel enthält die Zeichenkette, auf die das Muster passen soll, "PowerShell" mit einem großen 'S', während es im regulären Ausdruck klein geschrieben ist.

    Wenn der Mustervergleich case sensitive sein soll, dann kann man den Operator -cmatch verwenden. Zusätzlich gibt es noch -imatch, das genauso funktioniert wie -match, aber aus dessen Name explizit hervorgeht, dass es nicht zwischen Groß- und Kleinschreibung unterscheidet (und damit hilft, unerwartete Nebeneffekte zu vermeiden).

    Meistens will man bei komplexeren regulären Ausdrücken nicht nur wissen, ob ein Muster zutrifft, sondern auch auf welche Zeichenketten sie gepasst haben. Dies kann man über das Array $matches herausfinden. Die Variable $matches[0] enthält den gesamten String, auf den ein Muster passt, die folgenden Mitglieder des Arrays speichern die so genannten Group Matches. Es handelt sich dabei um Teile des Musters, die man in Klammern setzt, im obigen Beispiel wäre das "(\d)":

    Name Value
    ---- -----
    1 3
    0 Shell 3

    Eine Eigenart von -match und seinen Varianten besteht darin, dass es nur das erste Zutreffen eines Musters ermittelt, weitere Treffer werden nicht berücksichtigt.

    Select-String mit den Parametern -pattern und -AllMatches

    Wenn man alle Fundstellen für einen regulären Ausdruck in einer Zeichenkette ermitteln möchte, dann eignet sich für diese Aufgabe das Cmdlet Select-String. Dieses bietet einen Parameter namens -pattern, dem man einen regulären Ausdruck übergibt.

    Auch Select-String bricht nach dem ersten Zutreffen des Musters in einer Zeile ab. Dieses Verhalten kann man allerdings mit Hilfe des zusätzlichen Schalters -AllMatches abstellen:

    help about_regular_expressions| Select-String -pattern "ein.*" -AllMatches

    Möchte man hier alle Fundstellen ausgeben, dann kann man über die Matches-Eigenschaft der zurückgegebenen MatchInfo-Objekte iterieren (mit % als Alias für Foreach-Object im folgenden Beispiel) und aus ihnen den Wert der Eigenschaft Value auslesen:

    help about_reg | Select-String -pattern "ein.*" -AllMatches | %{$_.matches} | %{$_.value}

    Suchen und Ersetzen mit -replace

    Möchte man bestimmte Textmuster nicht nur finden, sondern durch andere Zeichenketten ersetzen, dann dient in PowerShell der Operator -replace diesem Zweck. Erwartungsgemäß benötigt er als Input zwei Angaben, nämlich den regulären Ausdruck und durch ein Komma getrennt den Ersetzungstext:

    "Einführung in PowerShell 2.0" -replace "\d\.", "3."

    Dieser Aufruf gibt anders als -match keinen Boolschen Wert zurück, der über das Zutreffen des Musters informiert, sondern die geänderte Zeichenkette. Im obigen Beispiel wird aus "2.0" ein "3.0".

    Oft möchte man einen Abschnitt, auf den ein regulärer Ausdruck zutrifft, nicht einfach durch eine feste Zeichenkette ersetzen, sondern dort Teile des ursprünglichen Textes wiederverwenden. In der Regel muss man zu diesem Zweck die Rückwärtsreferenzen mit Hilfe von Gruppierungen in den Variablen $1, $2, etc. einfangen. Bestimmte Werte, etwa $& (gesamter String, auf den das Muster zugetroffen hat), sind jedoch automatisch vorhanden.

    Wenn man zum Beispiel in der hosts-Datei bei allen IP-Adressen, die mit 192.168. beginnen, das 3. Oktett durch den Wert "99" ersetzen möchte, dann kann man dies so tun:

    $IPs = Get-Content -Path C:\Windows\system32\drivers\etc\hosts

    $IPs -replace "192\.168\.\d{1,3}\.(\d{1,3})", '192.168.99.$1'

    Das Teilmuster, das auf das letzte Oktett der IP-Adresse zutrifft, steht als einziges in runden Klammern. Daher lässt es sich über $1 ansprechen und in die neue IP-Adresse übernehmen.

    Bei der Formulierung eines solchen Befehls ist daran zu denken, dass der Ersetzungstext in einfachen Anführungszeichen stehen sollte, weil PowerShell die Variablen in doppelten Anführungszeichen schon expandiert, bevor sie an die RegEx-Engine übergeben werden. Da $1, $2, etc. in der Regel nicht vorbelegt sind, werden sie in einem solchen Fall durch die leere Zeichenkette ersetzt.

    Der Operator -replace belegt übrigens nicht wie -match die Variable $matches mit den Fundstellen für das angegebene Muster.

    Zeichenketten zerlegen mit -split

    Der Operator -split dient seinem Namen gemäß dazu, Strings an definierten Trennzeichen in mehrere Teil-Strings zu zerlegen. In den meisten Fällen dienen wörtlich zu interpretierende Zeichen als Delimiter, typischerweise sind das Tabulatoren, Semikolon oder Leerzeichen.

    Eine flexiblere Variante besteht darin, dass man die Positionen zum Auftrennen eines Strings über reguläre Ausdrücke definiert. Ein einfaches Beispiel könnte so aussehen:

    "Kapitel 1: Einführung in PowerShell 3.0" -split "(\d+|\s)"

    Dieser Aufruf trennt die angegebene Zeichenkette entlang aller Zahlen und Whitespace-Zeichen auf. Zu bedenken ist dabei jedoch, dass der Delimiter selbst in den Ergebnis-Strings nicht mehr vorhanden ist, also in diesem Beispiel alle Zahlen, Leerzeichen, Tabs, usw. eliminiert würden.

    Keine Kommentare