Eine Reihe von Dateien mit einem Datumsänderungs-Zeitstempel am Ende des Dateinamens umbenennen?

14

Angenommen, ich habe ein Verzeichnis mit einer Reihe von Dateien wie g.txt, in dem g.txt zuletzt am 20. Juni 2012 geändert wurde.

Wie würde ich alle Dateien (wie g.txt) mit dem letzten Änderungsdatum vom 20. Juni 2012, das am Ende angehängt wurde, stapelweise umbenennen?

InquilineKea
quelle

Antworten:

13

Quick-and-Dirty-Bash-Einzeiler zum Umbenennen aller (globalisierten) Dateien im aktuellen Verzeichnis von filename.txtnach filename.txt-20120620:

for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done

Ein unternehmungslustiger Bash-Nerd wird sicher einen Randfall finden, um ihn zu brechen. :)

Offensichtlich ist es nicht wünschenswert, zu prüfen, ob eine Datei bereits ein Datum hat, das am Ende wie ein Datum aussieht.

jgoldschrafe
quelle
2
+1, sieht gut aus. Sie können es etwas robuster machen, indem Sie '-' als erstes Argument für mv verwenden. wachen gegen filenaes, die mit '-' beginnen
cas
5
Was für eine Art von dateImplementierung ist das? Meine GNU datescheint nicht mit Eingaben umzugehen.
Manatwork
Coreutils 8.4 auf RHEL 6.
Jgoldschrafe
2
@jgoldschrafe, bist du sicher, dass der Code für dich richtig funktioniert? pastebin.com/nNYubf3A
Manatwork
5
gute Fangarbeit. Mein GNU-Datum 8.13 unterstützt auch nicht das Lesen von stdin. Es unterstützt die Verwendung der Mod-Zeit einer Datei mit "-r" - zB "Datum +% Y% m% d -r $ f", so dass stat in diesem speziellen Fall nicht einmal benötigt wird.
cas
18

hier ist eine version von goldschrafe's one-liner, die:

  • benutzt kein stat
  • funktioniert mit früheren Versionen von GNU Date
  • geht richtig mit Leerzeichen in den Dateinamen um
  • Bewältigt auch Dateinamen, die mit einem Bindestrich beginnen

    for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done

cas
quelle
1
Sie sollten es schaffen, date -r "$f" +%Y%m%doder es wird nicht funktionieren, wenn POSIXLY_CORRECTes in der Umgebung ist. Im Allgemeinen sollten Optionen vor anderen Argumenten stehen.
Stéphane Chazelas
Dies sollte die "richtige Antwort" sein
ungültiger
Natürlich brauchst du keine Zahnspange "${f}".
G-Man sagt, dass Monica am
aber wie würden Sie es so machen, dass die Daten, die wir vorangestellt haben, zB "Ymd-Dateiname"?
Zeitband
2

Obligatorischer zsh-Einzeiler (einmaliges Laden optionaler Komponenten nicht eingerechnet):

zmodload zsh/stat
autoload -U zmv
zmv -n '(*)' '$1-$(stat -F %Y%m%d +mtime -- $1)'

Wir verwenden das stateingebaute zsh/statModul und die zmvFunktion, um Dateien umzubenennen. Und hier ist ein Extra, das das Datum, falls vorhanden, vor die Verlängerung setzt.

zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'
Gilles 'SO - hör auf böse zu sein'
quelle
1

Wie ich verstanden habe, wissen wir nicht im Voraus, was das Änderungsdatum ist. Also müssen wir es aus jeder Datei holen, die Ausgabe formatieren und jede Datei so umbenennen, dass das Änderungsdatum in den Dateinamen enthalten ist.

Sie können dieses Skript als "modif_date.sh" speichern und ausführbar machen. Wir rufen es mit dem Zielverzeichnis als Argument auf:

modif_date.sh txt_collection

Wobei "txt_collection" der Name des Verzeichnisses ist, in dem sich alle Dateien befinden, die umbenannt werden sollen.

#!/bin/sh

# Override any locale setting to get known month names
export LC_ALL=c
# First we check for the argument
if [ -z "$1" ]; then
    echo "Usage: $0 directory"
    exit 1
fi

# Here we check if the argument is an absolute or relative path. It works both ways
case "${1}" in
  /*) work_dir=${1};;
  *) work_dir=${PWD}/${1};;
esac

# We need a for loop to treat file by file inside our target directory
for i in *; do
    # If the modification date is in the same year, "ls -l" shows us the timestamp.
    # So in this case we use our current year. 
    test_year=`ls -Ggl "${work_dir}/${i}" | awk '{ print $6 }'`
    case ${test_year} in *:*) 
        modif_year=`date '+%Y'`
        ;;
    *)
        modif_year=${test_year}
        ;;
    esac
    # The month output from "ls -l" is in short names. We convert it to numbers.
    name_month=`ls -Ggl "${work_dir}/${i}" | awk '{ print $4 }'`
    case ${name_month} in
            Jan) num_month=01 ;;
            Feb) num_month=02 ;;
        Mar) num_month=03 ;;
        Apr) num_month=04 ;;
        May) num_month=05 ;;
        Jun) num_month=06 ;;
        Jul) num_month=07 ;;
        Aug) num_month=08 ;;
        Sep) num_month=09 ;;
        Oct) num_month=10 ;;
        Nov) num_month=11 ;;
        Dec) num_month=12 ;;
        *) echo "ERROR!"; exit 1 ;;
    esac
    # Here is the date we will use for each file
    modif_date=`ls -Ggl "${work_dir}/${i}" | awk '{ print $5 }'`${num_month}${modif_year}
    # And finally, here we actually rename each file to include
    # the last modification date as part of the filename.
    mv "${work_dir}/${i}" "${work_dir}/${i}-${modif_date}"
done
Eine Linie
quelle
1
Lesen Sie die Manpage zu stat (1), um herauszufinden, wie Sie Ihr Skript um etwa 3/4 verkleinern können. Insbesondere gibt 'stat -c% Y' die Änderungszeit einer Datei in Sekunden seit der Epoche (1970-01-01 00:00:00) an. Dies kann dann als Eingabe für Datum (1) verwendet werden, um den Zeitstempel nach Bedarf zu formatieren. siehe jgoldschrafe's antwort oben für ein beispiel.
cas
@CraigSanders Der Vorteil ist, dass dieses Skript unter anderen Betriebssystemen als Linux funktioniert, die ein anderes statoder gar kein Dienstprogramm haben .
Gilles 'SO- hör auf böse zu sein'
Beachten Sie, dass das Parsen der Ausgabe von lsnicht zuverlässig ist . Bei einigen Unix-Varianten können Benutzer- und Gruppennamen Leerzeichen enthalten, wodurch die Ausrichtung der Datumsspalten beeinträchtigt wird.
Gilles 'SO- hör auf böse zu sein'
@giles: wahr, aber jeder vernünftige :-) würde GNU Coreutils (und alle anderen GNU-Tools) auf jedem Nicht-Linux-System installieren. Dies ist der einfachste Weg, um nicht nur einen guten Satz von Userland-Tools zu erhalten, sondern auch einen konsistenten Satz, unabhängig vom zugrunde liegenden Kernel.
cas
1
(Fortsetzung)… (5) Ein weiterer Fehler: Es wird davon ausgegangen, dass ein Datum / eine Uhrzeit, die ls als Datum und Uhrzeit angezeigt wird (statt als Datum und Jahr), im aktuellen Jahr liegen muss. Das ist nicht wahr. Es ist in den letzten sechs Monaten; Dies könnte im Vorjahr liegen (z. B. vom 27. September 2016 bis zum 31. Dezember 2016 in den letzten sechs Monaten). (6) Auf die Gefahr hin, Gregs Wiki (das @Gilles bereits zitiert hat) zu parrotieren, können Dateinamen, die Zeilenumbrüche und Leerzeichen enthalten, dazu führen, dass dies fehlschlägt. … (Fortsetzung)
G-Man sagt, dass Monica am
0

Hier ist eine Version von Cas 'One-Liner (basierend auf Goldschrafe's Oneliner), die mit Idempotenz erweitert wurde.

dh erweitert, um Dateien mit Datums- und Uhrzeitpräfix zu versehen und dies nur für diejenigen, die noch kein Datums- und Uhrzeitpräfix haben .

Anwendungsfall: hilfreich, wenn Sie dem Verzeichnis neue Dateien hinzufügen und denen, die noch keine 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
Grzegorz Wierzowiecki
quelle
Wenn die Zeitstempel Ihrer Dateien verschraubt sind und JPEGs sind, möchten Sie sie möglicherweise mit EXIF-Daten reparieren: for f in *.jpg ; do jhead -ft "$f" ; doneQuelle: unix.stackexchange.com/a/290755/9689
Grzegorz Wierzowiecki