Powershell-Banner

Powershell: Textinhalte suchen und ersetzen

Viele Texteditoren und IDEs bieten die Möglichkeit, Text in einem Dokument zu suchen und zu ersetzen. Wenn es allerdings darum geht, viele verschiedene Dateien nach festen Regeln zu bearbeiten (z. B. Regeln wie Ordnernamen, letzte Zugriffszeit, Dateigröße usw.), dann reichen Texteditoren in der Regel nicht aus und es muss programmatisch an die Sache herangegangen werden. Zum Glück sind Powershell und bash mächtig genug, dies zu erledigen und man muss nicht eigens dafür ein Programm schreiben.

Anwendungsfall

Ein konkretes Beispiel: Ich hatte letztens Java-Quellcode eines Lehrbuchs heruntergeladen und in einem Projekt abgespeichert. Das Problem dabei war, dass die Dateien zwar in unterschiedlichen Ordnern daherkamen, sie aber alle den gleichen Paketnamen hatten. Wenn man diese Dateien nun in einem Projekt laden und austesten möchte, müssen die Paketnamen erst per Hand angepasst oder alle Dateien in den gleichen Ordner verschoben werden. Teilweise hatten diese jedoch den gleichen Namen, was auch noch zu Namenskonflikten geführt hätte.

Screenshot eines VisualStudioCode-Fensters. Am linken Rand ist eine Ordnerstruktur zu erkennen: Der übergeordnete Ordner namens Blubb mit seinen Unterordnern ordner1 bis ordner3, in denen jeweils 3 unterschiedliche Java-Dateien sind. Im Hauptteil des Fensters wird aus dem jeweiligen Ordner der Inhalt einer Java-Datei angezeigt, die alle das Paket namens "blubb" haben.
Vorher: Problem mit Javadateien, gleiche Paketnamen, unterschiedliche Ordner

Lösungsansatz

Alle Dateien in ihren jeweiligen Ordnern behalten, dafür aber die Paketnamen anpassen. Da die Dateien alle nur eine Unterebene weiter anzutreffen sind, müssen nicht mehrere Ordnernamen als Pakethierarchie verkettet werden.

  1. Sammle alle Java-Datei des Ordner (inkl. Unterordner) in einer Liste
  2. Gehe dateiweise durch die Liste durch
  3. Lade den Inhalt der Datei (als Text)
  4. Benutze einen Regulären Ausdruck als Suchmuster
  5. Ersetze den Text, aber behalten Paketnamen dank Platzhalter
  6. Weiterleitung des veränderten Textes zum Überschreiben der Datei
    1. Set-Content kann ab der Pipe (|) auskommentiert werden. Dadurch wird der ersetzte Text als Vorschau in der Konsole ausgegeben aber nicht gespeichert
$dateien = $(Get-ChildItem -Recurse -Path D:\blubb\ -File -Filter *.java)

foreach($datei in $dateien) {	
	((Get-Content $datei.FullName) -replace "package (\w+);",  "package `$1.$($datei.Directory.Name);") | Set-Content $datei.FullName
}
Wie beim vorigen Screenshot von VisualStudioCode. Dieses mal haben die geöffneten Beispieldateien angepasste Paketnamen wie zum Beispiel blubb.ordner1. Ende gut, alles gut.
Nachher: Paketnamen wurden angepasst und können von Java verarbeitet werden

Zu beachten

Bei der Verwendung von Set-Content in einer Schleife kann auch mal was schiefgehen und dann wird möglicherweise der Dateiinhalt einer anderen Datei überschreiben oder der Inhalt wird gelöscht. Deswegen kann man Set-Content auskommentieren, falls man sich noch nicht sicher ist oder die optional -WhatIf Flag beim Befehl setzen. Letztere gibt dann eine Information aus, welche Datei überschrieben wird.


Links

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.