Tags: Datei-Management, PowerShell, Kommandozeile
Windows besitzt mit find und findstr bereits zwei Kommandozeilen-Tools, mit denen man Textdateien durchsuchen kann. Das PowerShell-Äquivalent dafür diesen Zweck ist Select-String, das gegenüber den alten Dienstprogrammen einige Vorteile bietet. Dazu gehört eine vollwertige Implementierung von regulären Ausdrücken.
Während find ein mager ausgestattetes Relikt aus DOS-Zeiten ist, implementiert findstr immerhin die wichtigsten Funktionen von grep unter Windows. Die PowerShell geht jedoch mit Select-String über die Möglichkeiten der beiden genannten Tools hinaus.
Sinnvolle Vorgabewerte
In seiner einfachsten Form besteht der Aufruf von Select-String darin, dass man ihm einen Dateinamen (bzw. ein Muster für Dateinamen unter Verwendung von Wildcards) sowie die zu suchende Zeichenkette übergibt:
Select-String -path index.html -pattern "Home"
In diesem Fall erfolgt die Ausgabe aller Zeilen, die Fundstellen enthalten, auf stdout, und zwar inklusive Zeilennummer.
Der Vergleich zwischen dem Suchbegriff und dem Inhalt der Datei erfolgt standardmäßig ohne Rücksicht auf Groß- und Kleinschreibung. Dies ist ein Fortschritt gegenüber den alten Tools, bei denen man dafür immer den Schalten /i angeben muss.
Hier ist es umgekehrt. Die eher seltene Suche, die zwischen Groß- und Kleinschreibung unterscheidet, muss man explizit über den Schalter -CaseSensitive aktivieren.
Der Wert des Parameter -pattern wird grundsätzlich als regulärer Ausdruck interpretiert. Für eine einfache Suche nach einer Zeichenkette wie im obigen Beispiel kann man stattdessen den Parameter -SimpleMatch verwenden:
Select-String -path index.html -SimpleMatch "Home"
Inverse Suche mit -NotMatch
Das grep-Äquivalent in Powershell unterstützt über -NotMatch auch eine inverse Suche, bei der alle Zeilen gefunden werden sollen, die das Suchmuster nicht enthalten.
Eine weitere Eingrenzung der Suche lässt sich erreichen, indem man bestimmte Dateien ausschließt, wenn man für den Parameter -path Wildcards verwendet:
Select-String -path *.* -exclude *.pdf,*.zip -Pattern "DO.*=" -NotMatch
Suche in Unterverzeichnissen nur mit Get-ChildItem
In diesem Fall würden im aktuellen Verzeichnis alle Dateien mit Ausnahme von ZIP-Archiven und PDFs durchsucht. Im Gegensatz zu find und findstr ist Select-String nicht in der Lage, rekursiv die Dateien in Unterverzeichnissen zu durchsuchen.
Wenn man das möchte, muss man sich weiterer Powershell-Mittel bedienen, indem man den Output von Get-ChildItem über eine Pipe an Select-String weiterleitet:
Get-ChildItem *.* -exclude *.pdf -recurse | Select-String -Pattern "DO.*="
Da die Auswahl der Dateien vollständig über Get-ChildItem erfolgt, kann sich der Aufruf von Select-String in diesem Fall auf die Übergabe des Suchmusters beschränken.
Suchergebnisse anpassen
Im Unterschied zu rein textorientierten Tools wie find gibt ein Cmdlet wie Select-String Objekte zurück, im konkreten Fall vom Typ MatchInfo.
Wenn man mit der relativ unübersichtlichen Anzeige von Pfad plus Dateiname plus Zeilennummer plus Zeile nicht zufrieden ist, dann kann man die gewünschten Eigenschaften gezielt mit Select-Object auswählen. So würde etwa
Select-String -path index.html -SimpleMatch "Home" |
select FileName, LineNumber
nur den Dateinamen und die Zeilennummer anzeigen, wo das Suchmuster gefunden wurde.
Über den Parameter -Context könnte man zusätzlich die Zahl der umgebenden Zeilen bestimmen.
Verwendung von MatchInfo-Eigenschaften
Eine weitere Eigenschaft namens Matches ist besonders praktisch, wenn man komplexere reguläre Ausdrücke verwendet. In diesem Fall kann man oft nicht sicher sein, auf welche Zeichenketten sie tatsächlich zutreffen. In diesem Fall würde
Select-String -path *.* -Pattern "DO.*=" | select -expand Matches
genau diese Übereinstimmungen anzeigen. Per Voreinstellung sieht man dabei aber nur den ersten Treffer pro Zeile. Um alle zu erhalten, muss man den Schalter -AllMatches hinzufügen.
String-Manipulationen mit den Fundstellen
Da sich die Ergebnisse von Select-String an alle möglichen Cmdlets weiterreichen lassen, ergeben sich dadurch fast unbegrenzte Möglichkeiten der Weiterverarbeitung.
Das beginnt mit der Formatierung der Ausgabe, indem man diese etwa durch Format-List schickt und dadurch eine wesentlich übersichtlichere Ausgabe erhält.
Natürlich stehen auch alle Funktionen für die String-Manipulation zur Verfügung, um die gefundenen Textstellen zu verändern:
select-string -path *.cmd -pattern "do.*=" |
foreach {$_.ToString().ToLower()}
In diesem Beispiel wird die Ausgabe in Kleinbuchstaben konvertiert, man könnte aber etwa genauso einen Substring extrahieren oder sie mit einer anderen Zeichenkette zusammenfügen.
Täglich Know-how für IT-Pros mit unserem Newsletter
Verwandte Beiträge
- Dateien zwischen Windows und Linux kopieren mit SCP und PowerShell
- Pfad zu einer Programmdatei finden
- Windows Terminal 1.6 Preview erhält GUI für Einstellungen, v1.5 nun offizielles Release
- PowerShell 7.1 (als Store-App) verfügbar, Updates für PSReadLine, SecretManagement und PowerShellGet
- JSON in PowerShell erzeugen und bearbeiten
Weitere Links
3 Kommentare
Guten Morgen,
ich habe eine Frage und zwar, ich habe eine Textdatei mit sehr vielen Wörtern in ca.300 Zeilen, und ich möchte dass mir nur 2 Bestimmte Wörter aus einer Zeile ausgelesen werden, wie funktioniert dass?
Guten Tag,
Ich möchte das Gleiche wissen. Ich kann die Zeile "selecten" in welcher der gesuchte Begriff ist. Jedoch möchte ich nur ein Wort als Ausgabe haben.
Wie funktioniert das?
Die Verwendung von MatchInfo-Eigenschaften kannte ich bisher nicht - danke für den Hinweis.