Wie ändere ich Ordner-Zeitstempel rekursiv in die neueste Datei?

15

Ich habe mich gefragt, ob jemand weiß, wie man die Zeitstempel von Ordnern rekursiv ändert, basierend auf dem letzten gefundenen Zeitstempel der Dateien in diesem Ordner.

Also zum Beispiel:

jon @ UbuntuPanther: / media / media / MP3s / Foo Fighters / (1997-05-20) Die Farbe und die Form $ ls -alF
insgesamt 55220
drwxr-xr-x 2 jon jon 4096 30.08.2010 12:34 ./
drwxr-xr-x 11 jon jon 4096 30.08.2010 12:34 ../
-rw-r - r-- 1 jon jon 1694044 18.04.2010 00:51 Foo Fighters - Doll.mp3
-rw-r - r-- 1 jon jon 3151170 18.04.2010 00:51 Foo Fighters - Genug Platz.mp3
-rw-r - r-- 1 jon jon 5004289 18.04.2010 00:52 Foo Fighters - Everlong.mp3
-rw-r - r-- 1 jon jon 5803125 18.04.2010 00:51 Foo Fighters - February Stars.mp3
-rw-r - r-- 1 jon jon 4994903 18.04.2010 00:51 Foo Fighters - Hey, Johnny Park! .mp3
-rw-r - r-- 1 jon jon 4649556 18.04.2010 00:52 Foo Fighters - Monkey Wrench.mp3
-rw-r - r-- 1 jon jon 5216923 18.04.2010 00:51 Foo Fighters - My Hero.mp3
-rw-r - r-- 1 jon jon 4294291 18.04.2010 00:52 Foo Fighters - My Poor Brain.mp3
-rw-r - r-- 1 jon jon 6778011 18.04.2010 00:52 Foo Fighters - New Way Home.mp3
-rw-r - r-- 1 jon jon 2956287 18.04.2010 00:51 Foo Fighters - See You.mp3
-rw-r - r-- 1 jon jon 2730072 2010-04-18 00:51 Foo Fighters - Up in Arms.mp3
-rw-r - r-- 1 jon jon 6086821 2010-04-18 00:51 Foo Fighters - Walking After You.mp3
-rw-r - r-- 1 jon jon 3033660 18.04.2010 00:52 Foo Fighters - Wind Up.mp3

Für den Ordner "(1997-05-20) Die Farbe und die Form" wurde der Zeitstempel auf 2010-04-18 00:52 festgelegt.

MonkeyWrench32
quelle

Antworten:

20

Sie können touch -ranstelle der aktuellen Zeit (oder touch --reference=FILE) den Zeitstempel einer anderen Datei verwenden.

Hier sind zwei Lösungen. In jeder Lösung ändert der erste Befehl die Änderungszeit des Verzeichnisses in die der neuesten Datei, die sich unmittelbar darunter befindet, und der zweite Befehl betrachtet den gesamten Verzeichnisbaum rekursiv. Wechseln Sie in das Verzeichnis ( cd '.../(1997-05-20) The Colour and The Shape'), bevor Sie einen der Befehle ausführen.

In zsh (entfernen Sie die Dzu ignorierenden Punktedateien):

touch -r *(Dom[1]) .
touch -r **/*(Dom[1]) .

Unter Linux (oder allgemeiner mit GNU find):

touch -r "$(find -mindepth 1 -maxdepth 1 -printf '%T+=%p\n' |
            sort |tail -n 1 | cut -d= -f2-)" .
touch -r "$(find -mindepth 1 -printf '%T+=%p\n' |
            sort |tail -n 1 | cut -d= -f2-)" .

Beachten Sie jedoch, dass diese keine Zeilenumbrüche in Dateinamen annehmen.

Gilles 'SO - hör auf böse zu sein'
quelle
Die Befehle funktionieren (ich habe die Linux-Befehle verwendet), aber es funktioniert nicht rekursiv. Ich habe es in meinem Stammordner (/ media / media / MP3s) ausgeführt und kein Glück mit den restlichen Künstlerverzeichnissen. Vielen Dank für Ihre bisherige Hilfe.
MonkeyWrench32
@ MonkeyWrench32: Ich habe deine Frage so beantwortet, wie ich sie verstanden habe. Möchten Sie den Befehl auf jedes darunter liegende Verzeichnis anwenden /media/media/MP3s? Dann in zsh: for d in /media/media/MP3s/**/*(/); do touch -r $d/*(Dom[1]) $d; done. Ohne zsh (aber wirklich, mit zsh ist es einfacher): Setze den Befehl in ein Skript und starte es find /media/media/MP3s -type d -execdir /path/to/the/script \;.
Gilles 'SO- hör auf böse zu sein'
Perfektion! Du bist ein zsh-Meister! : D
MonkeyWrench32
Wenn Sie verwenden, for d in ...wie können Sie das Folgende anpassen, damit es auch mit Ordnern funktioniert, die Leerzeichen enthalten? (Das fehlt noch in meiner Lösung)
Rubo77
@ rubo77 Ich verstehe nicht, wovon du sprichst. Alle Lösungen, die ich veröffentlicht habe, arbeiten mit Dateinamen, die Leerzeichen enthalten (einige von ihnen schlagen bei Dateinamen mit Zeilenumbrüchen fehl). Beachten Sie, dass einige meiner Lösungen zsh erfordern, was keine doppelten Anführungszeichen bei Variablensubstitutionen erfordert.
Gilles 'SO- hör auf böse zu sein'
3

Das ist nicht "rekursiv", sondern ändert nur alle Zeitstempel in einem Ordner. Wenn Sie das meinen, sind es zwei Schritte.

stat -c '%Y' filenamegibt den Zeitstempel von filenameund stat -c '%Y %n' *den Zeitstempel und den Dateinamen jeder Datei im Ordner aus, sodass der Dateiname der zuletzt geänderten Datei im aktuellen Ordner ermittelt wird:

mostrecent="`stat -c '%Y %n' * | sort -n | tail -n1 | cut -d ' ' -f '2-'`"

Am zweiten Gedanken, gibt es eine Art und Weise einfachen Weg , um den höchsten Zeitstempel in dem Ordner zu erhalten:

mostrecent="`ls -t | head -n1`"

Anschließend möchten Sie alle Dateien im Ordner so ändern, dass sie denselben Zeitstempel wie diese Datei haben. touch -r foo barändert sich barmit demselben geänderten Zeitstempel wie foo, sodass alle Dateien im Ordner denselben geänderten Zeitstempel haben wie Ihre zuletzt geänderte Datei:

touch -r "$mostrecent" *

Der Einzeiler ist also:

touch -r "`ls -t | head -n1`" *
Michael Mrozek
quelle
Das Parsen der Ausgabe von ls ist eine schlechte Idee , obwohl ich zugebe, dass es ein verlockender Fall ist. Es ist immer noch riskant, lsDateinamen zu ändern, die Nicht-ASCII-Zeichen enthalten. Wenn du Einzeiler willst, benutze zsh :-)
Gilles 'SO - hör auf, böse zu sein'
@ Gilles Es ist, aber ich habe noch kein Problem damit; Ich nehme an, weil meine Dateinamen keine Nicht-ASCII-Zeichen enthalten. Ihre Antwort ist jedoch besser
Michael Mrozek
2

Ich habe die Arbeit zusammengestellt und jetzt:

Dies wäre ein Skript, das alle Verzeichnisse /tmp/test/in den Zeitstempel der neuesten Datei in jedem Verzeichnis ändert :

#!/bin/bash
if [ -z "$1" ] ; then
  echo 'ERROR: Parameter missing. specify the folder!'
  exit
fi
#MODE=tail # change to newest file
MODE=head # change to oldest file
for d in "$1"/*/; do
  echo "running on $d"
  find "$d" -type d -execdir \
    echo touch --reference="$(find "$d" -mindepth 1 -maxdepth 1 -printf '%T+=%p\n' \
                              | sort | "$MODE" -n 1 | cut -d= -f2-)" "$d" \;
    # remove echo to really run it
done

Sie können einige Testdateien in / tmp wie folgt hinzufügen:

mkdir /tmp/test
cd /tmp/test
mkdir d1
mkdir d2
touch d1/text1.txt
sleep 1
touch d1/movie1.mov
touch d2/movie2.mov
sleep 1
touch d2/text2.txt
touch notthis.file
rubo77
quelle
1
Danke für deine Bearbeitung, es funktioniert! Obwohl das Echo das "wieder entfernt, sieht es zunächst so aus, als ob es fehlt, aber es funktioniert.
Rubo77
2

benutz einfach

find . -exec touch {} \;
DAZ
quelle
0

Ich verwende dieses Skript, um Ordner-Zeitstempel rekursiv auf den neuesten Inhalt zu setzen. (Es ist Gilles 'Antwort sehr ähnlich):

#! /bin/bash

# Change mtime of directories to that of latest file (or dir) under it, recursively
# Empty leaf directories, or dirs with only symlinks get the $default_timestamp

default_timestamp='1980-01-01 00:00:00'

dir="$1"

[ -d "$dir" ] || { echo "Usage: $0 directory" >&2; exit 1; }

find "$dir" -depth -type d | while read d; do
    latest=$(find "$d" -mindepth 1 -maxdepth 1 \( -type f -o -type d \) -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-)
    if [ -n "$latest" ]; then
        touch -c -m -r "$latest" "$d" \
            || echo "ERROR setting mtime of '$d' using ref='$f'" >&2
    else
        touch -c -m -d "$default_timestamp" "$d" \
            || echo "ERROR setting mtime of '$d' to default '$default_timestamp'" >&2
    fi
done
mivk
quelle
0

Ich habe den Befehl @Gilles zsh übernommen und für die Arbeit in Unterordnern verbessert, aber es scheint, dass zsh für den Teil ** / * (FDod) furchtbar ineffizient ist.

# Don't do this
for d in **/*(FDod); do touch -r "$d"/*(Dom[1]) "$d"; done

Die Anführungszeichen ermöglichen, dass Verzeichniseinträge mit Leerzeichen und Tabulatoren ordnungsgemäß funktionieren. Mit dem FD werden nicht leere Verzeichnisse gefunden, einschließlich der Verzeichnisse, die mit. Beginnen. Mit dem od wird zuerst in der Tiefe gesucht Art und Weise, so dass die übergeordneten Ordner Zeitstempel korrekt aktualisiert.

Beim Testen stellte ich fest, dass die Leistung und der Speicherbedarf für ** / * (FDod) verrückt waren (über 1,4 GB für nur 650.000 Ordner), und es wurde die gesamte Menge gelesen, bevor mit dem Berühren von Ordnern begonnen wurde. Nachdem es durch find / read ersetzt wurde, wurde es viel schneller, brannte keinen Speicher und begann fast sofort.

#! /usr/bin/env zsh
# Do this instead
find "$@" -depth -type d ! -empty -print0 |while IFS= read -r -d ''; do
    touch -r "$REPLY"/*(Dom[1]) "$REPLY"
done

Wenn Sie es nicht in einem Skript ausführen, ersetzen Sie "$ @" durch die Ordner, aus denen Sie es ausführen möchten.

Aaron Queenan
quelle
-1

Ich mochte die Dunkelheit der Shell-Befehle nicht wirklich und tat es schnell in Python.

Es setzt rekursiv alle Verzeichnis-mtimes auf die neueste nicht ausgeschlossene Datei / dir mtime innerhalb.

import os
import sys

EXCLUDE_FILES = ['.DS_Store']
EXCLUDE_DIRS = ['.git', '.hg']

def inheritMTime(path):
    for root, dirs, files in os.walk(path, topdown=False, followlinks=False):
        currentMaxMtime = None
        for subpath in files:
            if subpath in EXCLUDE_FILES:
                print "ignore file", os.path.join(root, subpath)
                continue
            currentMaxMtime = max(currentMaxMtime, os.lstat(os.path.join(root, subpath)).st_mtime)
        for subpath in dirs:
            if subpath in EXCLUDE_DIRS:
                print "ignore dir", os.path.join(root, subpath)
                continue
            currentMaxMtime = max(currentMaxMtime, os.lstat(os.path.join(root, subpath)).st_mtime)
        if currentMaxMtime is not None:
            os.utime(root, (currentMaxMtime, currentMaxMtime))

if __name__ == "__main__":
    for dir in os.listdir(sys.argv[1]):
        if os.path.isdir(dir):
            current = os.path.join(sys.argv[1], dir)
            inheritMTime(current)
schlaflos
quelle