Wie bekomme ich die erfassten Gruppen von Select-String?

69

Ich versuche, mit Powershell (Version 4) Text aus einer Reihe von Dateien unter Windows zu extrahieren:

PS > Select-String -AllMatches -Pattern <mypattern-with(capture)> -Path file.jsp | Format-Table

So weit, ist es gut. Das gibt eine schöne Reihe von MatchInfoObjekten:

IgnoreCase                    LineNumber Line                          Filename                      Pattern                       Matches
----------                    ---------- ----                          --------                      -------                       -------
    True                            30   ...                           file.jsp                      ...                           {...}

Als nächstes sehe ich, dass sich die Captures im Match-Mitglied befinden, also nehme ich sie heraus:

PS > Select-String -AllMatches -Pattern <mypattern-with(capture)> -Path file.jsp | ForEach-Object -MemberName Matches | Format-Table

Welches gibt:

Groups        Success Captures                 Index     Length Value
------        ------- --------                 -----     ------ -----
{...}         True    {...}                    49        47     ...

oder als Liste mit | Format-List:

Groups   : {matched text, captured group}
Success  : True
Captures : {matched text}
Index    : 39
Length   : 33
Value    : matched text

Hier höre ich auf. Ich habe keine Ahnung, wie ich weiter gehen und eine Liste der erfassten Gruppenelemente erhalten soll .

Ich habe versucht, ein weiteres hinzuzufügen | ForEach-Object -MemberName Groups, aber es scheint dasselbe wie oben zurückzugeben.

Am nächsten komme ich mit | Select-Object -Property Groups, was mir tatsächlich das gibt, was ich erwarten würde (eine Liste von Sets):

Groups
------
{matched text, captured group}
{matched text, captured group}
...

Aber dann kann ich die erfasste Gruppe nicht aus jedem von ihnen extrahieren. Ich habe versucht | Select-Object -Index 1, nur eines dieser Sets zu erhalten.


Update: eine mögliche Lösung

Es scheint, dass | ForEach-Object { $_.Groups.Groups[1].Value }ich durch Hinzufügen das bekommen habe, wonach ich gesucht habe, aber ich verstehe nicht warum - daher kann ich nicht sicher sein, ob ich das richtige Ergebnis erzielen kann, wenn ich diese Methode auf ganze Dateigruppen ausdehne.

Warum funktioniert es?

Als Randnotiz ergibt dies | ForEach-Object { $_.Groups[1].Value }(dh ohne die Sekunde .Groups) das gleiche Ergebnis.

Ich möchte hinzufügen, dass bei weiteren Versuchen der Befehl anscheinend durch Entfernen der Rohrleitungen verkürzt werden kann | Select-Object -Property Groups.

wässrig
quelle
1
Jedes Match hat eine implizite Gruppe 0, die selbst ein Match ist. In Ihrer GroupsFallkollektion gibt es also zwei Elemente: Übereinstimmung mit sich selbst und erste Erfassungsgruppe. Wenn Sie nur eine Gruppe erfassen möchten, müssen Sie diese mit angeben Groups[1].
user4003407

Antworten:

69

Schauen Sie sich Folgendes an

$a = "http://192.168.3.114:8080/compierews/" | Select-String -Pattern '^http://(.*):8080/(.*)/$' 

$aist jetzt ein MatchInfo( $a.gettype()) es enthält eine MatchesEigenschaft.

PS ps:\> $a.Matches
Groups   : {http://192.168.3.114:8080/compierews/, 192.168.3.114, compierews}
Success  : True
Captures : {http://192.168.3.114:8080/compierews/}
Index    : 0
Length   : 37
Value    : http://192.168.3.114:8080/compierews/

Im Gruppenmitglied finden Sie, wonach Sie suchen, damit Sie schreiben können:

"http://192.168.3.114:8080/compierews/" | Select-String -Pattern '^http://(.*):8080/(.*)/$'  | % {"IP is $($_.matches.groups[1]) and path is $($_.matches.groups[2])"}

IP is 192.168.3.114 and path is compierews
JPBlanc
quelle
Ohne die führenden Leerzeichen wird das Sternchen in den Erfassungsgruppen in der zweiten Zeile der Antwort (wo Sie es zuweisen $a) nicht angezeigt . Ich habe versucht zu bearbeiten, habe aber eine Fehlermeldung erhalten, da meine Bearbeitung weniger als sechs Zeichen umfasst. IOW, erscheinen die Einfanggruppen als (.)statt (.*)wie beabsichtigt.
Marc Sherman
Wie lautet die% {""} -Syntax in der letzten Anweisung?
Koja
2
%ist ein Alias ​​für ForEach-Object. dann können Sie jedes Objekt mit behandeln $_.
JPBlanc
7

Gemäß den Powershell-Dokumenten zu regulären Ausdrücken> Gruppen, Erfassungen und Ersetzungen :

Bei Verwendung des -matchOperators erstellt Powershell eine automatische Variable mit dem Namen$Matches

PS> "The last logged on user was CONTOSO\jsmith" -match "(.+was )(.+)"

Der von diesem Ausdruck zurückgegebene Wert ist nur true| false, aber PS wird die Hashtabelle hinzufügen$Matches

Wenn Sie also ausgeben $Matches, erhalten Sie alle Erfassungsgruppen:

PS> $Matches

Name     Value
----     -----
2        CONTOSO\jsmith
1        The last logged on user was
0        The last logged on user was CONTOSO\jsmith

Und Sie können auf jede Erfassungsgruppe einzeln mit der folgenden Punktnotation zugreifen:

PS> "The last logged on user was CONTOSO\jsmith" -match "(.+was )(.+)"
PS> $Matches.2
CONTOSO\jsmith

Zusätzliche Ressourcen :

KyleMit
quelle
1

Das hat für meine Situation funktioniert.

Verwenden der Datei: test.txt

// autogenerated by script
char VERSION[21] = "ABCDEFGHIJKLMNOPQRST";
char NUMBER[16] = "123456789012345";

Holen Sie sich die NUMMER und die VERSION aus der Datei.

PS C:\> Select-String -Path test.txt -Pattern 'VERSION\[\d+\]\s=\s\"(.*)\"' | %{$_.Matches.Groups[
1].value}

ABCDEFGHIJKLMNOPQRST

PS C:\> Select-String -Path test.txt -Pattern 'NUMBER\[\d+\]\s=\s\"(.*)\"' | %{$_.Matches.Groups[1
].value}

123456789012345

Jeremy Whitcher
quelle
1

Späte Antwort, aber um mehrere Übereinstimmungen und Gruppen zu wiederholen, verwende ich:

$pattern = "Login:\s*([^\s]+)\s*Password:\s*([^\s]+)\s*"
$matches = [regex]::Matches($input_string, $pattern)

foreach ($match in $matches)
{
    Write-Host  $match.Groups[1].Value
    Write-Host  $match.Groups[2].Value
}
Pedro Lobito
quelle
-1

Dieses Skript greift die angegebene Erfassungsgruppe eines regulären Ausdrucks aus dem Inhalt einer Datei ab und gibt die Übereinstimmungen an die Konsole aus.


$fileIst die Datei, die Sie laden möchten,
$cgist die Erfassungsgruppe, die Sie abrufen möchten,
$regexdas Muster für reguläre Ausdrücke



Beispieldatei und ihr zu ladender Inhalt:

C: \ some \ file.txt

This is the especially special text in the file.



Beispiel Verwendung: .\get_regex_capture.ps1 -file "C:\some\file.txt" -cg 1 -regex '\b(special\W\w+)'

Ausgabe: special text


get_regex_capture.ps1

Param(
    $file=$file,
    [int]$cg=[int]$cg,
    $regex=$regex
)
[int]$capture_group = $cg
$file_content = [string]::Join("`r`n", (Get-Content -Raw "$file"));
Select-String -InputObject $file_content -Pattern $regex -AllMatches | % { $_.Matches.Captures } | % { echo $_.Groups[$capture_group].Value }
kayleeFrye_onDeck
quelle