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.

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.
- Sammle alle Java-Datei des Ordner (inkl. Unterordner) in einer Liste
- Gehe dateiweise durch die Liste durch
- Lade den Inhalt der Datei (als Text)
- Benutze einen Regulären Ausdruck als Suchmuster
- Ersetze den Text, aber behalten Paketnamen dank Platzhalter
- Weiterleitung des veränderten Textes zum Überschreiben der Datei
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 }

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
- Paketnamen bei Java:
- Doku zu Get-Content:
- https://docs.microsoft.com/de-de/powershell/module/Microsoft.PowerShell.Management/Get-Content?view=powershell-5.0
- Für die eigene PS-Version aufrufen per:
Get-Help Get-Content -Online
- Doku zu Set-Content:
- https://docs.microsoft.com/de-de/powershell/module/Microsoft.PowerShell.Management/Set-Content?view=powershell-5.0
- Für die eigene PS-Version aufrufen per:
Get-Help Set-Content -Online
- Info zu regulären Ausdrücken:
- Powershell im Speziellen:
Get-Help about_Regular_Expressions
und hier - Direkt online testen https://regex101.com/
- Powershell im Speziellen: