Dateien mit regulären Ausdrücken suchen

Unter Windows durchsucht man die lokale Festplatte meist nur mit Hilfe des “Suchen”-Dialogs aus dem Startmenü. Diese Methode erweist sich jedoch als unzureichend, wenn etwas komplexere Abfragen durchgeführt werden sollen. Spätestens, wenn der Dateiname oder der Pfad mit einem regulären Ausdruck verglichen werden soll, ist schluss. Aber wer braucht schon einen “Suchen”-Dialog, wenn Microsoft mit der Powershell völlig neue Möglichkeiten geschaffen hat?

Woher, wohin

Die Powershell gehört seit Windows 7 zum Lieferumfang von Windows. Zu finden ist sie - nach der Installation - im Ordner “Zubehör” oder einfach über die Startmenüsuche (Stichwort: Powershell).

Dateiliste

Um in Powershell die Dateiliste des aktuellen Ordners zu erhalten genügt es, das CmdLet Get-ChildItem aufzurufen. Wer es gerne kürzer haben möchte, kann die Aliase dir oder ls verwenden.

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        08.08.2012     14:51            .eclipse
d----        30.08.2012     08:34            Desktop
d----        29.08.2012     17:12            Eigene Dateien
d-r--        29.09.2011     10:46            Favorites
d----        25.05.2010     10:32            Lokale Einstellungen
d-r--        27.08.2012     15:23            My Documents
d-r--        16.03.2010     07:59            Start Menu
d---s        04.08.2010     11:34            UserData
-----        22.09.2010     10:24       1582 _viminfo

Natürlich möchte man auch manchmal versteckte Dateien sehen. Get-ChildItem -force erledigt das.

Weniger ist mehr

## Ok, und wo sind jetzt die tollen Filtermöglichkeiten? Das ist eine berechtigte Frage. Da die Powershell ihre Informationen in Form von Objekten verwaltet, gibt es viel mehr Informationen zu einem Verzeichniseintrag als man mit bloßem Auge sieht. Die Zeile Get-ChildItem|Select-Object -First 1|Get-Member * gibt eine Übersicht der Eigenschaften und Methoden eines Verzeichniseintrags zurück1:

Name                      MemberType
----                      ----------
Mode                      CodeProperty
Create                    Method
CreateObjRef              Method
CreateSubdirectory        Method
Delete                    Method
Equals                    Method
GetAccessControl          Method
GetDirectories            Method
GetFiles                  Method
GetFileSystemInfos        Method
GetHashCode               Method
GetLifetimeService        Method
GetObjectData             Method
GetType                   Method
InitializeLifetimeService Method
MoveTo                    Method
Refresh                   Method
SetAccessControl          Method
ToString                  Method
PSChildName               NoteProperty
PSDrive                   NoteProperty
PSIsContainer             NoteProperty
PSParentPath              NoteProperty
PSPath                    NoteProperty
PSProvider                NoteProperty
Attributes                Property
CreationTime              Property
CreationTimeUtc           Property
Exists                    Property
Extension                 Property
FullName                  Property
LastAccessTime            Property
LastAccessTimeUtc         Property
LastWriteTime             Property
LastWriteTimeUtc          Property
Name                      Property
Parent                    Property
Root                      Property
BaseName                  ScriptProperty

Gerade die Einträge, welche den “MemberType” “Property” besitzten sind für uns interessant:

Eigenschaft Beschreibung
Attributes Attribute der Datei oder des Verzeichnisses.
CreationTime Erstellungszeitpunkt der Datei oder des Verzeichnisses.
CreationTimeUtc Enthält den Wert von CreationTime in UTC/GMT.
Exists Gibt an ob die Datei existiert. Sollte bei allen Dateien die über Get-ChildItem gefunden werden “true” sein.
Extension Gibt die Dateierweiterung der Datei oder des Verzeichnisses an. Dies ist normalerweise der Text nach dem letzten “.”.
FullName Gibt den vollständigen Namen der Datei oder des Verzeichnisses (inkl. des Pfades) an.
LastAccessTime Zeitpunkt des letzten Zugriffs auf die Datei oder das Verzeichnis.
LastAccessTimeUtc Enthält den Wert von LastAccessTime in UTC/GMT.
LastWriteTime Zeitpunkt des letzten Schreibzugriffs auf die Datei oder das Verzeichnis.
LastWriteTimeUtc Enthält den Wert von LastWriteTime in UTC/GMT.
Name Enthält den Dateinamen bzw. Verzeichnisnamen ohne Pfad.
Parent Enthält ein Objekt, welches das übergeordnete Verzeichnis repräsentiert.
Root Enthält ein Objket, welches das Laufwerk repräsentiert, in welchem die Datei abgelegt wurde.

Natürlich kann Get-ChildItem auch verwendet werden um andere Powershell-Namespaces zu durchlaufen (z. B. kann man darüber auch in der Registry suchen). Aber das ist eine andere Geschichte.

Gut, und wie filtert man jetzt nach dem ganzen Zeug?

Hierfür gibt es das Where CmdLet, welches sich auch durch ein Fragezeichen abkürzen lässt. Diesem CmdLet übergibt man ein Stück Powershell-Script, mit welchem man dann die Dateien filtern kann. Zum Beispiel zeigt Get-ChildItem|Where {\$_.Name -match "^b.*"} alle Dateien an, deren Name mit einem “b” beginnt2. Innerhalb des Code-Blocks, welcher von Match verwendet wird, dient die Variable \$_ dazu, das aktuell geprüfte Element zu bestimmen. Der Block muss dann entweder “true” (1) oder “false” (0) zurückliefern, je nach dem, ob man die Datei im Ergebnis haben will, oder nicht. Der langweiligste Code-Block wäre damit Get-ChildItem|Where {1}. Er würde alle Dateien selektieren.

Sieht man sich die Hilfe zu den Vergleichsoperatoren3 an, erhält man gute Hinweise, welche Vergleichsoperatoren in Powershell noch möglich sind:

Operator Beschreibung
-eq Prüft auf Gleichheit.
-ne Prüft auf Ungleichheit (Gegenteil von -eq).
-gt Größer als.
-ge Größer oder gleich.
-lt Kleiner als.
-le Kleiner oder gleich.
-like Übereinstimmungsprüfung welche das Wildcard (*) unterstützt. Ähnelt den Filtern in normalen DOS-Befehlen wie dir.
-notlike Gegenteil von -like. Trifft immer dann zu, wenn keine Übereinstimmung gefunden wird.
-match Übereinstimmungsprüfung mit einem regulären Ausdruck (Groß-/Kleinschreibung wird ignoriert).
-cmatch Übereinstimmungsprüfung mit einem regulären Ausdruck (Groß-/Kleinschreibung wird beachtet).
-notmatch Gegenteil von -match. Trifft immer dann zu, wenn keine Übereinstimmung gefunden wird.
-contains Prüft ob eine Liste den angegebene String enthält.
-notcontains Gegenteil von -contains. Trifft immer dann zu, wenn das Element nicht in der Liste gefunden wird.

Wie man sieht, bietet der Where-Filter eine Menge an Möglichkeiten.

Tiefer und tiefer

Manchmal möchte man nicht nur in der aktuellen Ebene des Verzeichnisbaums, sondern auch in Unterordnern suchen. Dies erlaubt der Paramter -Recurse. Get-ChildItem C: -Recurse liefert also alle Dateien auf dem Laufwerk C:.

Beispiele

Hier noch einige Beispiele, wie man diese mächtige Suchfunktion effektiv nutzen kann:

Beispiel 1

Get-ChildItem|Where {\$_.Name -match "^b.*"}

Das hatten wir oben schon. Es zeigt alle Dateien an, welche mit einem “b” beginnen. Hierbei wird nicht zwischen Groß- und Kleinschreibung unterschieden.

Beispiel 2

Get-ChildItem -Force|Where {\$_.Attributes -contains "Hidden"}

Zeigt alle versteckten Dateien an.

Beispiel 3

Get-ChildItem -Force|Where {\$_.Length -gt 1000}

Sucht alle Dateien, deren Größe 1000 Byte übersteigt.

Beispiel 4

Get-ChildItem C: -Recurse|Where {(New-Timespan \$_.CreationTime \$(Get-Date)).TotalDays -lt 10}|Select-Object FullName,CreationTime

Gibt den Pfad aller Dateien aus, die in den letzten 10 Tagen erstellt wurden. Hierbei wird das CmdLet New-Timespan verwendet, welches aus zwei Zeitangaben einen Zeitraum bildet.

Beispiel 5

Get-ChildItem|Where {\$_.Attributes -contains "Directory"}|ForEach-Object {\$_|Add-Member -name Length -membertype NoteProperty -value \$(\$_|Get-ChildItem -Recurse |Measure-Object -Property length -sum).Sum -passthru}

Ermittelt die Größe der einzelnen Unterordner des aktuellen Ordners. Normalerweise wird die Eigenschaft “Length” für Ordner nicht befüllt. Über ein ForEach-Konstrukt wird aber für jedes Directory (Attributfilter) die Length-Eigenschaft mit der Summe der Größen der Kinder belegt. Dies geschieht über das CmdLet Add-Member, welches eine neue Eigenschaft zu einem Powershell-Objekt hinzufügt.

Beispiel 6

Get-ChildItem -Recurse -Force|Sort-Object -Property Length -Descending|Select -First 20|Select FullName, Length|Out-GridView

Zeigt eine grafische Liste der zwanzig größten Dateien in allen Unterordnern des aktuellen Ordners an.

Beispiel 7

Get-ChildItem|Where {! \$_.PSIsContainer}|ForEach-Object {\$_|Add-Member -name Key -membertype NoteProperty -value \$(Get-Random) -passthru}|Sort-Object -Property Key|Select-Object FullName

Gibt die Namen (inkl. Pfad) der Dateien im aktuellen Verzeichnis (PSIsContainer sorgt dafür, dass Unterordner übersprungen werden) in zufälliger Reihenfolge aus. Hierfür wird jeder Datei ein zufälliger Schlüssel “Key” hinzugefügt und anschließend nach diesem sortiert. Kann verwendet werden, um zufällige Playlists ohne doppelte Einträge zu erzeugen.

  1. Hier habe ich etwas geschummelt und die Spalte “Definition” entfernt. Sonst bricht die Liste in einigen Browsern sehr unschön um. 

  2. Wer seine Kollegen beeindrucken möchte kann auch die Kurzform ls|? {\$_.Name -match "^b.*"} verwenden. 

  3. Get-Help about_comparison_operators -full