Zum Hauptinhalt springen

Muster finden mit dem -match Operator

Für Vergleiche mit regulären Ausdrücken verwenden Sie die Vergleichsoperatoren -match und -notmatch. Sie funktionieren ähnlich wie -like und -notlike und geben $true zurück, wenn das Muster gefunden wurde, das der reguläre Ausdruck beschreibt. Die Suchergebnisse werden in einer Hashtable zurückgegeben, die in der Standardvariablen $matches gespeichert ist. Achten Sie darauf, dass reguläre Ausdrücke in anderen Sprachen normalerweise Groß-Kleinschreibesensitiv sind, man Powershell aber mit -cmatch explizit sagen muss, dass Groß- und Kleinschreibung unterschieden werden sollen.

Betrachten wir dafür die folgenden Beispiele:

'Hallo Welt' -match '[ABC]+' 'Hallo Welt' -match '[A-Z]{2,3}' 'Hallo Welt' -match '\w*\s'
  1. [ABC]: Die eckigen Klammern stellen genau ein Zeichen dar. Die Buchstaben in den eckigen Klammern beschreiben die erlaubten Werte an dieser Position. Dieses Konstrukt wird Character-Class (Zeichenklasse) genannt. Das + hinter der Klammer ist der Quantifizierer. Er steht für ein- bis beliebig häufiges Auftreten des vorstehenden Ausdrucks.
  2. [A-Z] steht für einen Zeichenbereich, hier also alle Buchstaben von A-Z. {2,3} ist wieder ein Quantifizierer und gibt die untere und obere Grenze  für den gesuchten Wert an. Der Ausdruck [A-Z] muss also für einen Treffer genau zwei- oder drei Mal auftreten.
  3. \w steht für "word" und ist Platzhalter für alle Buchstaben, Zahlen sowie den Unterstrich _. \s steht für Leerzeichen, Tabulatoren und Zeilenumbrüche. * ist ein Quantifizierer und steht für eine beliebige Anzahl von Zeichen. Er unterscheidet sich von + dadurch, dass auch kein einziges Zeichen ein Treffer ist. Das Suchmuster beschreibt also eine Gruppe zusammenhängender Wortzeichen, gefolgt von einem Leerzeichen (Space, Tabulator oder Zeilenumbruch).

Das Ergebnis des Vergleichs mit -match wird mit $true quittiert, wenn das Muster gefunden wurde, ansonsten mit $false. Hier die Ergebnisse der obigen Beispiele:

 

'Hallo Welt' -match '[ABC]+'
> True
$Matches
> Name Value
> ---- -----
> 0    a

 Das Zeichen A ist im Text vorhanden, und zwar einmal. Die Hashtable $matches beinhaltet das gefundene Ergebnis, den Buchstaben a.

'Hallo Welt' -match '[A-Z]{2,3}'
True
$Matches
Name Value
---- -----
0    Hal

Gesucht ist ein beliebiger Buchstabe, der zwei- oder dreimal auftritt. $matches beinhaltet den ersten Treffer, Hal (die ersten drei Buchstaben des Textes). Tatsächlich trifft dieses Suchmuster auch auf die Kombinationen lo und Wel zu, aber $matches speichert immer nur den ersten Treffer. Um alle Muster anzuzeigen, die dem regulären Ausdruck entsprechen anzuzeigen, müssen Sie auf die .NET-Klasse [Regex] zurückgreifen (s. unten).

'Hallo Welt' -match '\w*\s'
> True
$Matches
> Name Value
> ---- -----
> 0    Hallo

Gesucht ist eine beliebige Kette von "word"-Zeichen (Buchstabe, Zahl oder Unterstrich), gefolgt von einem Leerzeichen. $matches beinhaltet "Hallo ". Beachten Sie, dass $matches den gesamten Treffer beinhaltet, also auch das dem Hallo folgende Leerzeichen, da es im regulären Ausdruck mit angegeben worden ist.

Ein Quantifizierer ist standardmäßig gierig (greedy) , was nichts anderes bedeutet, als dass er immer die maximale Anzahl möglicher Zeichen in das Suchergebnis aufnimmt. Im Beispiel

'Hallo Welt' -match '[A-Z]{2,3}'

haben wir über den Quantifizierer zwei oder drei Zeichen zur Auswahl gegeben, der reguläre Ausdruck liefert aber drei Zeichen zurück – die größtmögliche Anzahl. Um die kleinstmögliche Trefferzahl zurückzuliefern, müssen Sie den Ausdruck faul (lazy) machen, indem Sie hinter den Quantifizierer ein "?" setzen.

'Hallo Welt' -match '[A-Z]{2,3}'
> $Matches
Name Value
---- -----
0    Ha

Achten Sie auch darauf, dass es bei regulären Ausdrücken wichtig ist, wo ein Steuerzeichen steht. Das ?hat nämlich mehrere Bedeutungen, die sich abhängig vom Ort, an dem es angegeben ist, ändern. Hinter einem Quantifizierer definiert es diesen als lazy, aber ohne vorangehenden Quantifizierer ist ? selbst einer. Es hat dann nämlich die Bedeutung 0 oder 1 Zeichen, auch darstellbar als {0,1}. Anders gesagt ist das dem ? vorstehende Zeichen optional.

( Dir $PSHOME\*.ps* -Recurse ).fullname | Where-Object { $_ -match '.psd?1' }

Dieses Beispiel gibt für jede Datei, die die Endung .ps1 oder .psd1 hat, True zurück, da das Fragezeichen hier als Quantifizierer verwendet wird und das vorstehende d optional macht. 

-match hat eine nützliche Eigenart. Wenn man ein Array mit -match überprüft, wird nicht True oder False zurückgeliefert, sondern die Objekte, für die die Überprüfung True ergeben hat. Geben Sie also

( Dir $PSHOME\*.ps* -Recurse ).fullname -match '.psd?1'

ein, bekommen Sie die Dateinamen zurück, die -match als dem Muster entsprechend gefunden hat. Das Ergebnis des Befehls wirkt allerdings merkwürdig, denn im Ergebnis stehen wider Erwarten auch Dateien mit der Endung .ps1xml. Ein wichtiger Unterschied zwischen regulären Ausdrücken und einfachen Platzhaltern ist nämlich, dass ein regulärer Ausdruck immer dann einen Treffer meldet, wenn das Suchmuster irgendwo im zu durchsuchenden Text auftritt, während ein einfaches Suchmuster (eine sogenannte global Expression) exakt übereinstimmen muss. Hierzu ein einfaches Beispiel:

Get-Command -Command [ABC]*

> CommandType Name                       Version   Source
> ----------- ----                       -------   ------
> Alias       ac -> Add-Content
> Alias.      Add-ProvisionedAppxPackage   3.0      Dism
> Alias       Add-ProvisioningPackage      3.0      Provisioning
…
> Cmdlet      Copy-VMFile                  2.0.0.0  Hyper-V

$CommandNames = (Get-Command -Name Write-Warning).name
$CommandNames -match '[ABC]\w*'
> $true

$Matches
> Name Value
> ---- -----
> 0    arning

Im ersten Teil des Beispiels wird nach allen Kommandos gesucht, die mit A, B oder C beginnen. Wie man an der Ausgabe sehen kann, endet die Ausgabe im Beispiel mit dem Cmdlet Copy-VMFile, da es das letzte Kommando ist, das mit dem Buchstaben C anfängt (auf Ihrem Rechner kann das natürlich ein anderes Cmdlet sein). Die drei Punkte in der Ausgabe sind ein Auslassungszeichen, da deutlich mehr Kommandos zurückgegeben worden sind als hier angezeigt.

Lässt man sich nur das Cmdlet Write-Warning zurückgeben, und wendet das Suchmuster (in leichter Abwandlung, da das * bei einem regulären Ausdruck ein Quantifizierer ist) mit dem match Operator an, wird $true zurückgeliefert. $matches beinhaltet nun "arning". Das ist auch völlig korrekt, denn wir haben mit dem Ausdruck ausgesagt, dass wir die Zeichen [ABC] suchen, gefolgt von beliebigen Buchstaben, Zahlen oder dem Unterstrich. Wo [ABC] stehen muss, haben wir offengelassen.

Wenn Sie den Operator -match einsetzen, erhalten Sie immer nur den ersten gefunden Text, der Ihrem Suchmuster entspricht. Alle folgenden Treffer werden nicht mehr angegeben. Wenn Sie alle Treffer benötigen, können Sie auf die Klasse [Regex] des .NET-Frameworks zurückgreifen. Sie enthält eine Statische Methode Matches(), die für jeden gefundenen Treffer ein Match-Objekt zurückliefert, das in der Eigenschaft Value den Suchwert enthält:

 

[regex]$RegEx = '[a-z]{2,3}'
$RegEx.Matches('Hallo Welt') | Select-Object -Property value

> Value
> -----
> all
> elt

 

Quantifizierer

Beispiel

Bedeutung

+

[ABC]+

Mindestens 1 oder mehr Zeichen

*

[^ABC]*

0 oder mehr Zeichen Zeichen

{1,3}

[A-Z]{1,3}

Bereich, hier 1 – 3 Zeichen

{4,}

\d{4,}

Bereich, hier 4 oder mehr Zeichen

?

\.psm?1

Dieses Zeichen ist optional (.ps1 oder .psm1)

 

?

 

a+?

Hinter einem Quantifizierer nimmt ? eine andere Bedeutung an. Während ein regulärer Ausdruck normalerweise die maximale Anzahl von Zeichen in Capture-Group aufnimmt (Beim Text 'aaaaaaaa' wäre das Suchergebnis beim Quantifizierer ebenfalls 'aaaaaaaa', da + bedeutet 1 bis unendlich viele Zeichen, ist +? be-reits mit dem kleinstmöglichen Treffer zufrieden, hier also 'a'. Da-für gibt es beim Text 'aaaaaaaa' allerdings 8 Treffer, nicht nur ei-nen.

|

\.exe|.\cmd

Oder (.exe oder .cmd)