Benennen Sie Dateien um, die groß geschrieben werden sollen, ohne jedoch Auswirkungen auf Dateierweiterungen zu haben

7

Ich verwende dies in einem Kundenverzeichnis, um Dateien umzubenennen, wobei der erste Buchstabe jedes Wortes gemäß seiner Anfrage großgeschrieben wird:

rename 's/\b(\w)/\u$1/g' *

Das funktioniert gut, aber es wird auch der erste Buchstabe der Erweiterung großgeschrieben. Ich verwende dies, um Folgendes zu beheben:

rename 's/\.Txt$/.txt/' *.Txt

Das funktioniert in Ordnung, wenn die meisten Dateien in einem Ordner dieselbe Erweiterung haben (im Allgemeinen wahr), ist aber ein Schmerz, wenn sie sehr gemischt sind.

Um dieses Problem zu umgehen, habe ich ein kleines Skript erstellt, das so aussieht (nicht lachen!):

#!/bin/bash
rename 's/\.Txt$/.txt/' *.Txt
rename 's/\.Doc$/.doc/' *.Doc
rename 's/\.Docx$/.docx/' *.Docx
...
rename 's/\.Xlsx$/.xlsx/' *.Xlsx

Ich ignoriere die Fehler 'Kann * .Txt * .txt nicht umbenennen: Keine solche Datei oder kein solches Verzeichnis' und wenn ich eine fehlende Erweiterung finde, füge ich diese Zeile einfach meinem Skript hinzu.

Ich denke nicht, dass dies von Bedeutung sein wird, aber die Dateien befinden sich auf einem Windows-Server-Fileshare, aber ich greife mit Ubuntu 16.04LTS darauf zu. Wenn es wichtig ist, kann ich sie zuerst auf mein lokales Laufwerk kopieren, einen Befehl in Ubuntu ausführen und die Dateien bei Bedarf zurück verschieben.

Gibt es eine Möglichkeit, den ersten Umbenennungsbefehl zu ändern, um die Erweiterungen zu ignorieren und als Kleinbuchstaben zu belassen? Kann ich den neuen Befehl in einem übergeordneten Verzeichnis ausführen und ihn durch alle Unterverzeichnisse rekursieren lassen?

Alan
quelle
Also mit anderen Worten, Sie filename.txtwerden Filename.txt, richtig? Kannst du ein Beispiel geben ?
Sergiy Kolodyazhnyy
Hallo Sergiy - Ja, das wäre ein korrektes Beispiel. Dies wäre eine andere: 'Alan's file.txt' wird zu 'Alan's File.txt'
Alan

Antworten:

7

Eine Möglichkeit, dies zu erreichen, könnte darin bestehen, Negative Lookbehind zu verwenden, um nur mit der Wortgrenze - Wortzeichenfolge übereinzustimmen , wenn ihr keine wörtliche Periode vorausgeht, z

$ ls
alan's file.txt  bar.txt  foo

dann

$ rename -n 's/(?<!\.)\b\w*/\u$&/g' *
rename(alan's file.txt, Alan'S File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)

Angenommen, Sie möchten auch vermeiden, die Pluralisierung zu aktivieren s, können wir dies ändern

$ rename -n 's/(?<![.'\''])\b\w*/\u$&/g' *
rename(alan's file.txt, Alan's File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)

oder auch

$ rename -n 's/(?<![[:punct:]])\b\w*/\u$&/g' *
rename(alan's file.txt, Alan's File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)
Steeldriver
quelle
Perfekt! Ich werde dieses verwenden: rename -n 's/(?<![.'\''])\b\w*/\u$&/g' * Vielen Dank für Ihre Hilfe!
Alan
@Alan Stellen Sie sicher, dass Sie den Befehl ausführen, um sicherzustellen, dass die richtigen Umbenennungen ausgegeben werden, und entfernen Sie dann den Befehl, um ihn -ntatsächlich umzubenennen.
NoOneIsHere
5

Dadurch wird der erste Buchstabe jedes Wortes mit Ausnahme der letzten Erweiterung groß geschrieben:

rename -n 's/\b(.+?)\b/\u$1/g; s/(.+)\.(.)/$1\.\l$2/' *

Ich habe mit diesen Dateien getestet:

$ ls -1
'a file with a '$'\n''new line.foo'
'a file with spaces.txt'
justonelongfilename.ext
no-extensions-here
this.has.many.extensions.pdf

Und es wird sie umbenennen als:

$ rename -n 's/\b(.+?)\b/\u$1/g; s/(.+)\.(.)/$1\.\l$2/' *
a file with a 
new line.foo -> A File With A 
New Line.foo
a file with spaces.txt -> A File With Spaces.txt
justonelongfilename.ext -> Justonelongfilename.ext
no-extensions-here -> No-Extensions-Here
this.has.many.extensions.pdf -> This.Has.Many.Extensions.pdf

Der Trick besteht darin, zuerst jeden ersten Buchstaben groß zu schreiben, die Erweiterungen zu ignorieren und dann zurück zu gehen und die Erweiterung in Kleinbuchstaben zu schreiben:

  • s/\b(.+?)\b/\u$1/g;: Das .+?ist ein nicht gieriges Muster, was bedeutet, dass es die kürzestmögliche Übereinstimmung findet. Da es durch Wortgrenzen ( \b) verankert ist , werden alle Wörter gefunden (alle wegen des Finales g). Diese werden dann durch die großgeschriebene Version von sich selbst ( \l$1) ersetzt.

  • s/(.+)\.(.)/$1\.\l$2/: das .+ist gierig, so wird es die längstmögliche Übereinstimmung finden. Dies bedeutet die längste Zeichenfolge bis zum Ende ., danach die Erweiterung (falls vorhanden). Wir ersetzen die Übereinstimmung durch alles vor der Erweiterung ( $1), a .und die Erweiterung durch den ersten Buchstaben, der wieder in Großbuchstaben geschrieben wird ( \l$2).


Rekursion ist auch einfach genug. Wenn Ihre Shell bash ist (wenn Sie es nicht wissen, ist es wahrscheinlich), können Sie die Globstar-Option verwenden, mit der **0 oder mehr Unterverzeichnisse übereinstimmen:

shopt -s globstar

Führen Sie nun den Befehl zum Umbenennen wie folgt aus (dies funktioniert auch für alle Dateien in Ihrem aktuellen Verzeichnis):

rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' **

Verwenden Sie **/*.*anstelle von nur Dateien oder Verzeichnisse mit Erweiterungen **.

Alternativ können Sie Folgendes verwenden find:

find /path/to/dir -exec rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' {} +

Und um auf diese Dateien und Verzeichnisse mit einer Erweiterung zu beschränken:

find /path/to/dir -name '*.*' -exec rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' {} +

Beachten Sie, dass alle diese Lösungen sowohl Verzeichnisse als auch Dateien fröhlich umbenennen . Wenn Sie das nicht wollen, achten Sie darauf, wo Sie es wiederholen sollen, oder geben Sie ihm ein spezifischeres Muster wie *.txt.


Entfernen Sie in allen Beispielen das -n, damit sie tatsächlich etwas tun. Die-nUrsachenrename, einfach zu drucken, was es tun würde und eigentlich nichts zu tun. Nützlich zum Testen.

Terdon
quelle
Intelligenter Zug, bei dem alle Anfangsbuchstaben groß geschrieben und dann die Erweiterung verkleinert werden. + 1'ed
Sergiy Kolodyazhnyy
Hallo Terdon: Ich habe es gerade getestet rename -n 's/\b(.+?)\b/\u$1/g; s/(.+)\.(.)/$1\.\l$2/' *und es funktioniert fast, aber es nutzt auch die Possessiven von Alan's. Sieht so aus, als hätte SteelDriver unten eine Antwort mit rename -n 's/(?<![.'\''])\b\w*/\u$&/g' * Vielen Dank für Ihre Hilfe!
Alan
4

Am sinnvollsten wäre es, alle "Wörter" (unter Verwendung der Wortgrenze \bund unter Bezugnahme $1auf ein erstes Zeichen) einschließlich der Erweiterung anzugehen , dann aber die Erweiterung selbst in Kleinbuchstaben zu schreiben:

$ prename -nv 's/\b(.)/\u$1/g;s/^(.*)\.(.*)/$1.\l$2/' *                                                                                                                
another filename trispaced.txt renamed as Another Filename Trispaced.txt
filename_with_underschore.txt renamed as Filename_with_underschore.txt
one filename.txt renamed as One Filename.txt

Beachten Sie, dass dies für Dateinamen mit Unterstrichen nicht funktioniert, dh "Wort" -Grenzen werden bei Leerzeichen berücksichtigt (Tabulatoren, Leerzeichen, Zeilenumbrüche - die hoffentlich sowieso nicht im Dateinamen enthalten sein sollten).

Beachten Sie die Verwendung von prenamefür die Portabilität auf ksh, wobei renamees sich tatsächlich um einen integrierten Befehl handelt, nicht um die eigenständige perlausführbare Datei.

Sergiy Kolodyazhnyy
quelle
Hallo Sergiy, wenn ich das mache, muss ich am Ende des Befehls jede mögliche Erweiterung im Array auflisten? Es scheint auch umzubenennen alan's file.txtals Alan's file.txt(das zweite Wort wird nicht groß geschrieben).
Alan
@ Alan ah, also wolltest du, dass alle Wörter des Dateinamens groß geschrieben werden? Können Sie bitte Ihren ursprünglichen Beitrag bearbeiten, um diese Informationen aufzunehmen? Was Erweiterungen betrifft - ja, das wäre richtig, ein "Array" aller möglichen Kombinationen.
Sergiy Kolodyazhnyy
Hallo Sergiy - es heißt jetzt rename files with first letter of each word being capitalisedist das okay? In Bezug auf das Array könnte ich tun *.*?
Alan
@ Alan ja, *.*wäre in Ordnung, wenn es nur einen .im Dateinamen geben würde, dh nein foo.bar.txt. Danke für die Bearbeitung, übrigens, ich werde jetzt daran arbeiten, meine Antwort zu bearbeiten
Sergiy Kolodyazhnyy
@Sergiy *.*sollte alle nicht versteckten Dateien mit einer Erweiterung abgleichen , einschließlich foo.bar.txt, *.*sollte also gut funktionieren. Sie müssen keine Liste mit Erweiterungen angeben.
Terdon
1

Verwenden Sie einfach rename 's/\b(\w)/\u$1/' *OHNE das g-Flag.
Das g-Flag bedeutet "global = mehrmals ausführen". Sie machen das erste Mal im Dateinamen und möchten das zweite Mal nicht in Großbuchstaben schreiben, oder?

V-Mark
quelle
Hallo V-Mark - das habe ich versucht, aber es benennt 'zz alan.txt' in 'Alans file.txt' um (es wird nur das erste Wort großgeschrieben, aber nicht die anderen Wörter. Sie wollen, dass jedes Wort groß geschrieben wird).
Alan
@ Alan Das wäre viel einfacher zu verstehen, wenn Sie nur einige Beispiele in Ihre Frage aufnehmen würden und in was sie umbenannt werden sollen. Bitte stellen Sie sicher, dass Sie genau sind, Ihr Kommentar hier besagt, dass zz alan.txtumbenannt wurde, Alan's file.txtwas nicht sehr wahrscheinlich ist :)
Terdon
@Alan Was ist, wenn Sie Ihre ursprüngliche Umbenennung beibehalten, aber die Erweiterung mit Kleinbuchstaben versehen? rename 's/(.*)\.(\w)(.*)/$1.\l$2$3/' *Dies macht das Wort vor dem letzten Punkt klein. Also von Qwe.Asd.Zxcbis Qwe.Asd.zxc `
V-Mark
... und Sie können diese Umbenennungen zusammenstellen ...
V-Mark
Hallo V-Mark - Ich bin mir nicht sicher, wie sich das von dem unterscheidet, was ich gerade mache (wenn auch wahrscheinlich effizienter). Ich würde immer noch zwei Befehle ausführen?
Alan