
Nehmen wir also an, ich habe ein Verzeichnis mit einer Reihe von Dateien wie g.txt, wobei g.txt zuletzt am, sagen wir, 20. Juni 2012 geändert wurde.
Wie kann ich alle Dateien (z. B. g.txt) stapelweise umbenennen und dabei das letzte Änderungsdatum vom 20. Juni 2012 anhängen?
Antwort1
hier ist eine Version von Goldschrafes Einzeiler:
verwendet keine Statistik
funktioniert mit früheren Versionen von GNU date
verarbeitet Leerzeichen in Dateinamen korrekt
kommt auch mit Dateinamen klar, die mit einem Bindestrich beginnen
for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done
Aktualisierung 2021-03-20
Meine Antwort auf diese Frage beschäftigt mich schon seit Jahren (na ja, nur wenn ich mich daran erinnere – an Tagen wie heute, wenn sie wieder ein Upvote bekommt), also aktualisiere ich sie endlich. Meine ursprüngliche Antwort oben funktioniert noch, aber die aktualisierte Antwort unten ist besser.
WiebeliebigBatch-Datei-Umbenennungsvorgang, sollte dies mit demperl rename
Dienstprogramm, nicht mit einer umständlichen Shell-For-Schleife.
Das Perl-Umbenennungsprogramm ist im Grunde eine spezialisierte Skriptsprache, mit der Sie JEDEN Perl-Code zum Umbenennen von Dateien verwenden können, von einfachen s/search/replace/
regulären Ausdrucksoperationen (die für die meisten Umbenennungsaufgaben ausreichen) bis hin zu komplexen mehrzeiligen Skripts.
z.B
rename -n 'BEGIN {use Date::Format};
die $! unless -f $_;
next if (m/-\d{8}$/);
my $ts=(stat($_))[9];
my $dt=time2str("%Y%m%d",$ts);
s/$/-$dt/;' *.txt
Dies erfordert nur Perl und das Date::Format
Modul (ein Modul, das so nützlich ist, dass es auf jedem System mit Perl installiert werden sollte. IMO ist es zusammen mit dem Date::Parse
Modul des Autors Graham Barr,sollenTeil der Kernmodulbibliothek von Perl sein, ist es aber nicht, daher müssen Sie es mit cpan
oder einem Distributionspaket wie dem Debian- libtimedate-perl
Paket installieren).
Übrigens überspringt dieses Skript alle Dateien, deren Dateiname scheinbar bereits ein Datum (also 8 Ziffern) enthält.
oder für eine elegantere Version, die das Datum vor die Dateierweiterung setzt (sofern vorhanden):
rename -n 'BEGIN {use Date::Format; use File::Basename};
die $! unless -f $_;
my ($filename,$dirs,$suffix) = fileparse($_,qr/\.[^.]*/);
next if (m/-\d{8}${suffix}$/);
my $ts=(stat($_))[9];
my $dt=time2str("%Y%m%d",$ts);
s/${suffix}$/-${dt}${suffix}/;' *.txt
Für diese Version gelten keine zusätzlichen Anforderungen, da das File::Basename
Modul, soweit ich mich erinnern kann (mindestens ein Jahrzehnt, wahrscheinlich schon länger), als Standard-Kernmodul in Perl enthalten ist.
Notiz:Beide rename
oben genannten Skripte verwenden die Option „Dry-Run“ von rename -n
(auch bekannt als --nono
), sodass die Ergebnisse vor der Anwendung getestet/simuliert werden können. Entfernen Sie -n
(oder ersetzen Sie es durch -v
für eine ausführliche Ausgabe), wenn Sie sicher sind, dass es das gewünschte Ergebnis liefert.
Beachten Sie außerdem:wie mit jedem anderen Perl- rename
Skript können hiermit Dateinamen umbenannt werden, die in der Befehlszeile und/oder über die Standardeingabe angegeben wurden. So können Sie beispielsweise alle TXT-Dateien im aktuellen Verzeichnis und allen Unterverzeichnissen umbenennen:
find . -type f -iname '*.txt' -print0 |
rename -0 --nofullpath -n '..........'
Übrigens habe ich hier die Option rename
--nofullpath (auch bekannt als -d
, --filenmame
, --nopath
) von verwendet, um sicherzustellen, dass nur der Dateinamenteil aller gefundenen Dateipfade umbenannt wird. Dies ist in diesem speziellen Fall nicht erforderlich (da die Beispiel-Umbenennungsskripte nur das Ende des Dateinamens ändern), ist aber im Allgemeinen eine gute Idee, wenn Sie den Pfad und den Dateinamen nicht umbenennen möchten (z. B. würde ein Umbenennungsskript, das 's/ //g'
Leerzeichen aus Dateinamen entfernen möchte, versuchen, alle Leerzeichen im Pfad sowie im Dateinamen ohne zu entfernen --nofullpath
, was wahrscheinlich zu einem Fehler führen würde).
Endlich:verwechseln Sie das Perl-Umbenennungsskript (auch bekannt als File::Rename
, oder manchmal prename
unter Fedora und RedHat genannt, oder perl-rename
) nicht mit anderen Programmen namens „Umbenennung“. NurDieses Perl-basierte Umbenennungsprogramm kann Dateien mit beliebigem Perl-Code umbenennen, wie oben gezeigt. Jedes andere Umbenennungsprogramm verfügt über andere Funktionen und andere und inkompatible Befehlszeilenoptionen.
Sie können überprüfen, ob Sie die richtige Umbenennung installiert haben:
$ rename -V
/usr/bin/rename using File::Rename version 1.13, File::Rename::Options version 1.10
Die ausführbare Datei heißt auf Ihrem System möglicherweise prename
oder perl-rename
. Versuchen Sie es mit diesen Namen und passen Sie die obigen Beispiele an, um den richtigen ausführbaren Namen zu verwenden.file-rename
-V
Antwort2
Schneller und einfacher Bash-Einzeiler zum Umbenennen aller (globbierten) Dateien im aktuellen Verzeichnis von filename.txt
in filename.txt-20120620
:
for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done
Ich bin sicher, ein unternehmungslustiger Bash-Nerd wird einen Grenzfall finden, um es kaputt zu machen. :)
Offensichtlich werden dadurch nicht die gewünschten Dinge erledigt, wie etwa die Überprüfung, ob eine Datei am Ende bereits etwas enthält, das wie ein Datum aussieht.
Antwort3
Obligatorischer zsh-Einzeiler (das einmalige Laden optionaler Komponenten nicht mitgerechnet):
zmodload zsh/stat
autoload -U zmv
zmv -n '(*)' '$1-$(stat -F %Y%m%d +mtime -- $1)'
Wir verwenden das stat
Builtin aus demzsh/stat
Modul, und daszmv
Funktion zum Umbenennen von Dateien. Und hier ist noch eine Extrafunktion, die das Datum vor die Erweiterung setzt, falls vorhanden.
zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'
Antwort4
Hier ist die Version von cas' Oneliner (basierend auf goldschrafes Oneliner), erweitert mitIdempotenz,
ie erweitert um Präfixe für Dateien mit Datum, Uhrzeit undDies ist nur für diejenigen zu tun, die noch kein Datums-/Uhrzeitpräfix haben.
Anwendungsfall: hilfreich, wenn Sie dem Verzeichnis neue Dateien hinzufügen und denjenigen Dateien, die noch keines haben, ein Datums-/Uhrzeitpräfix hinzufügen möchten.
for f in * ; do
if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
fi;
done