Rolf B: For ... (Powershell != cmd.exe)

Beitrag lesen

Hallo Gerhard,

oookay.

Angenommen, deine Projektdateien liegen in C:\Foo\Bar. Dann wäre es dieser Powershell-Befehl (alles auf einer Zeile):

get-childitem C:\Foo\Bar\*.shtml -file -recurse | Rename-Item -NewName {[System.IO.Path]::GetFileNameWithoutExtension($_.Name) + ".php"}

get-childitem ist das Cmdlet zum Auflisten eines Datencontainers. Bei Powershell kann das das Dateisystem sein, oder die Registry, oder ein paar andere Sachen. Hier ist es der Ordner C:\Foo\Bar und seine Unterordner, und darin die *.shtml Dateien.

-file heißt: Finde nur Dateien. Einen Ordner test.shtml, falls es ihn gibt, wollen wir nicht umbenennen. Oder doch? Dann lass -file weg.

-recurse ist das, wonach es aussieht: Wenn's eine Ordnerstruktur gibt, durchlaufe sie rekursiv

| ist das Pipe-Zeichen: Die Ausgabe von Befehl 1 wird als Eingabe von Befehl 2 verwendet.

Der Unterschied zwischen Powershell und vielen anderen Shells ist, dass es sich hierbei NICHT um Text handelt, sondern um eine Array, ein richtiges .net Array, von richtigen .net Objekten. In diesem Fall Objekte vom Typ System.IO.FileSystemInfo.

Ein Powershell Cmdlet, das Pipe-Input verarbeiten kann, ist im Stande, ein solches Array zu durchlaufen. So auch das Cmdlet rename-item. Damit kann man Einträge in einem Speichersystem umbenennen, beispielsweise im Dateisystem.

Das Rename-Item Cmdlet braucht natürlich den neuen Namen, und den übergibt man ihm über den -NewName Parameter. Und hier kann ich nicht einfach eine Zeichenkette angeben. "*.php" würde als neuer Name nicht verstanden. Ich muss anders auf den alten Namen Bezug nehmen. Und deshalb übergebe ich einen Script Block, also so ein Dings in geschweiften Klammern. Ein Script-Block ist eine Art primitiver Funktion, ohne Name und ohne explizite Angabe von Parametern. Das Rename-Item Cmdlet ruft ihn für jede Datei, die es umbenennen soll, neu auf. Innerhalb des Script-Blocks ist die Variable $_ verfügbar (alle Powershell-Variablen beginnen mit $), in der das Rename-Item Cmdlet das gerade verarbeitete FileSystemInfo-Objekt bereitstellt.

Innerhalb des Scriptblocks benutze ich nun eine .net Klasse: System.IO.Path. Die eckigen Klammern sagen Powershell, dass dies eine .net Klasse ist. Diese Klasse hat eine statische Methode GetFileNameWithoutExtension, die einfach den letzten Punkt im Dateinamen sucht und alles, was davor steht, zurückgibt. Genau wie PHP verwendet Powershell den :: Operator, um auf statische Methoden einer Klasse zuzugreifen. Aber anders als PHP verwendet es den + Operator, um Strings zu verketten.

Viele Beispiele im Netz schlagen vor, den Script-Block so zu schreiben: { $_.Name.replace(".shtml", ".php") }. Also einfach .shtml durch .php ersetzen. Das ist kürzer, sicher, aber kann in die Hose gehen, wenn eine Datei den String ".shtml" mitten im Namen trägt und nicht am Ende. GetFileNameWithoutExtension ist die sicherere Alternative.

Tja. Nicht schön, nicht klein, aber sollte funktionieren.

Rolf

--
sumpsi - posui - obstruxi