Eine interessante kleine Aufgabenstellung: ein Skript hat versehentlich tausende von Dateien mit einer verkehrten Extension generiert. Alle Dateien heissen .jpgjpg statt einfach nur .jpg. Gestandene Shell-Benutzer reparieren sowas natürlich mit einem formschönen Einzeiler. Das ist einfach, und eigentlich lohnt es sich nicht da lange drüber nachzudenken. Es sei denn man kommt auf die Idee, das zeitlich zu optimieren…

Im konkreten Fall — es geht um etwa 6000 Dateien — dauert die Optimierung länger als das was an Laufzeitgewinn rauskommt. Wenn wir also schon keine Zeit gewinnen, dann wenigstens Erkenntnis. :-)

Also, mein erster Ansatz ist es intuitiv, alle Dateien zu suchen, für jede Datei den neuen Namen festzulegen und dann umzubenennen. Machen wir eine Trockenübung bei laufender Stopuhr:

Das führt zu einer Laufzeit von erstaunlichen 21,443 Sekunden!

Halbwegs moderne Shells wie die Bash beherrschen Stringmanipulation, dazu muss man nicht zwingend auf sed zurückgreifen. Im TLDP steht wie es geht, so finde ich dort unter ‚Substring Removal‘ den richtigen Ansatz:

Das drückt die Zeit für die gleichen Testdaten schon auf 0,811 Sekunden. Soweit ich weiss haben wir uns damit zwar einen Bashismus eingehandelt, aber das ist heutzutage vielleicht schon egal.

Wenn wir aber schon Kompatibilität aufgeben können wir — schliesslich sind wir in einer hochmodernen Zsh — gleich in die Vollen gehen:

Ich habe noch nie rekursives Globbing (die zsh-lovers-Manpage hat mir verraten wie das geht) benutzt, aber nach nur 0,165 Sekunden war klar: es funktioniert. :-)

Oh, da man hier auch denken könnte dass das Betriebssystem den Dateibaum cached: nein, das ist nicht so. Wenn ich die Einzeiler mehrfach absetze, auch in anderen Reihenfolgen, kommen immer wieder vergleichbare Ergebnisse raus.

Da die effizienteste Methode auch gleichzeitig die am schnellsten zu tippende ist denke ich, dass die — wenn ich auswendig gewusst hätte wie das geht — in jeder Hinsicht die erste Wahl gewesen wäre. Aber ich kenne mich: wenn ich das ein paar Tage nicht benutze muss ich erst wieder recherchieren. Und dann falle ich doch wieder auf das bewährte sed zurück…