Suchen Sie die neueste Datei nach Änderungsdatum

38

Wie würde ich vorgehen, wenn ich die neueste Datei (mtime) in einem (großen) Verzeichnis mit Unterverzeichnissen suchen möchte?

Viele Beiträge, die ich gefunden habe, weisen auf eine Variation von hin ls -lt | head(amüsanterweise schlagen viele vor, dass ls -ltr | taildies dasselbe, aber weniger effizient ist).

Andererseits könntest du

find . -type f -exec ls -lt \{\} \+ | head

Dies reicht auf jeden Fall für so viele Dateien aus, wie mit einem Befehl angegeben werden können. Wenn Sie also ein großes Verzeichnis haben, -exec...\+werden separate Befehle ausgegeben. daher wird jede Gruppe nach sich selbst sortiert, lsjedoch nicht über die Gesamtmenge; Der Kopf nimmt daher den letzten Eintrag der ersten Charge auf.

Irgendwelche Antworten?

Reich
quelle
Übrigens brauchen Sie keinen dieser Backslashes.
Enzotib
@enzotib: du tust ( \ + ), sonst bekommst dufind: missing argument to '-exec'
ordne den
@arrange: Ich habe diesen Fehler nicht, da er +keine Bedeutung hat bash, also keine Notwendigkeit, ihn zu umgehen .
Enzotib
@enzotib: du hast recht, mein fehler, sorry
arrangiere den

Antworten:

46

Sie müssen externe Befehle (as ls) nicht erneut ausführen, da findSie durch die -printfAktion alles tun können, was Sie benötigen :

find /path -printf '%T+ %p\n' | sort -r | head
Enzotib
quelle
1
Ja, ich habe es mir ausgedacht, find . -type f -exec stat --format=%y \{\} \+ | sort -r | head -n1aber Ihre Lösung ist weitaus sauberer!
Rich
3
Anhängen | cut -d ' ' -f2, um nur den Dateinamen zu erhalten
qwr
Sie können die Ausgabe auch so auswählen head, dass sie eine bestimmte Anzahl von Zeilen enthält. Ich brauchte nur die erste Zeile, also benutzte ichhead -n 1
Timmah
8

Ich hatte heute ein ähnliches Problem, aber ich habe es ohne angegriffen find. Ich brauchte etwas Kurzes, das ich überfahren konnte ssh, um die zuletzt bearbeitete Datei in meinem Ausgangsverzeichnis zurückzugeben. Das ist ungefähr das, was ich mir ausgedacht habe:

ls -tp | grep -v /$ | head -1

Die -pOption zum lsHinzufügen eines grep -vabschließenden Schrägstrichs zu Verzeichnissen, das Entfernen von Zeilen, die mit einem Schrägstrich enden (auch bekannt als alle Verzeichnisse) und das head -1Begrenzen der Ausgabe auf eine einzelne Datei.

Dies ist viel weniger ausführlich als die Verwendung, findwenn Sie nur den Dateinamen zurückgeben möchten.

Pat Regan
quelle
Dies behandelt keine Unterverzeichnisse.
Clément
4

Dies ist auf meinem System schneller als printf, obwohl ich nicht verstehe, warum

find /path -type f -exec stat -c "%y %n" {} + | sort -r | head
ordnen
quelle
Ich bestätige, ist schneller.
Enzotib
Noch ein Punkt, ... | sort -r | head -n1 | cut -d " " -f 4-wenn Sie nur den Dateinamen erhalten möchten.
林果 皞
Ich habe gerade festgestellt sort -r, dass der Dateiname falsch ist, wenn mehrere Zeilen vorhanden sind.
林果 林果
2

EDIT: Ich denke, dieser Beitrag ist nicht "nicht besonders nützlich", wie ich dachte, es war. Dies ist eine sehr schnelle Lösung, die nur den Überblick über die zuletzt geänderte Datei behält (anstatt die gesamte Liste der Dateien zu sortieren):

find . -type f -printf '%T@ %p\n' | awk 'BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; } { if ($1 > mostrecenttime) { mostrecenttime = $1; mostrecentline = $0; } } END { print mostrecentline; }' | cut -f2- -d ' '

Um die Übersichtlichkeit zu gewährleisten, sollten Sie die Informationen wie folgt auf mehrere Zeilen verteilen:

find . -type f -printf '%T@ %p\n' | awk '
    BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; }
    {
        if ($1 > mostrecenttime)
            { mostrecenttime = $1; mostrecentline = $0; }
    }
    END { print mostrecentline; }' | cut -f2- -d ' '

Ende der Bearbeitung


Kein besonders nützlicher Beitrag, aber da bei 'Anordnen' die Geschwindigkeit diskutiert wurde, dachte ich, ich würde dies teilen.

Bei den Lösungen von arrang und enzotib werden alle Dateien im Verzeichnis mit ihren MTimes aufgelistet und anschließend sortiert. Wie Sie wissen, ist das Sortieren nicht erforderlich, um das Maximum zu finden. Das Maximum kann in linearer Zeit ermittelt werden, aber das Sortieren dauert n log (n) [Ich weiß, der Unterschied ist nicht viel, aber dennoch;)]. Ich kann mir keine saubere Art und Weise vorstellen, dies umzusetzen. [BEARBEITEN: Eine ordentliche (wenn auch schmutzig aussehende) und schnelle Implementierung, die oben bereitgestellt wurde.]

Nächstbeste Sache - Um die zuletzt bearbeitete Datei in einem Verzeichnis zu finden, suchen Sie rekursiv die zuletzt bearbeitete Datei in jedem Unterverzeichnis der Ebene 1. Lassen Sie diese Datei das Unterverzeichnis darstellen. Sortieren Sie nun die Dateien der Ebene 1 zusammen mit den Vertretern der Unterverzeichnisse der Ebene 1. Wenn die Anzahl der Dateien und Unterverzeichnisse der Ebene 1 in jedem Verzeichnis nahezu konstant ist, sollte dieser Prozess linear mit der Gesamtzahl der Dateien skaliert werden.

Das habe ich mir ausgedacht, um das umzusetzen:

findrecent() { { find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1; }
findrecent .

Ich habe dies ausgeführt und eine Reihe von find: findrecent: No such file or directoryFehlern erhalten. Grund: -exec of find läuft in einer anderen Shell. Ich habe versucht, findrecent in .bashrc, .xsessionrc zu definieren, aber dies hat nicht geholfen. Am Ende bin ich zum Putten übergegangen

#!/bin/bash
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

in einem Skript findrecentin meinem Pfad aufgerufen und dann ausgeführt.

Ich ließ dies laufen, wartete und wartete ohne Ausgabe. Nur um sicherzugehen, dass ich mich nicht mit Endlosschleifen befasst habe, auf die ich die Datei geändert habe

#!/bin/bash
echo "$1" >&2
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

und versuchte es erneut. Es hat funktioniert - aber 1 Minute 35 Sekunden auf meinem Homefolder gedauert - Arrangements und Enzotibs Lösungen haben 1,69 bzw. 1,95 Sekunden gedauert!

Soviel zur Überlegenheit von O (n) gegenüber O (n log (n))! Verdammt du Funktionsaufruf Overhead! [Oder vielmehr Skriptaufruf Overhead]

Aber dieses Skript lässt sich besser skalieren als die früheren Lösungen, und ich wette, es wird auf der Speicherbank von Google schneller laufen als sie. D

S Prasanth
quelle
2

Verwenden Sie perlin Konjunktin mit find:

 find my_directory -type f -printf '%T@\t%p\n' | perl -ane '@m=@F if ($F[0]>$m[0]); END{print $m[1];}'

Sie erhalten den Namen der Datei mit der größten Epoche == zuletzt geänderten Datei.

MUY Belgien
quelle
1

Es ist bei weitem nicht so modern, aber es ist auch möglich, dies mit Midnight Commander zu erreichen : Suche nach *, Anzeige des Ergebnisses, Sortierung nach Änderungszeit in umgekehrter Reihenfolge.

Offensichtlich ist es ein bisschen langsamer als find- mein Home-Verzeichnis mit 922000 Dateien wurde mcin knapp 14 Minuten sortiert, während findweniger als 5 ausgegeben wurden - aber es gibt einige Vorteile:

  • Ich würde wahrscheinlich länger als die 9-Minuten-Differenz damit verbringen, einen richtigen Find-Aufruf zu erfinden :)

  • geringere Wahrscheinlichkeit eines Fehlers (vergessen, -r für Sortierung usw. anzugeben - erneut starten)

  • Es ist möglich, mit der Ergebnismenge zu spielen, indem die Sortierreihenfolge usw. geändert wird - ohne die Dateien erneut abzufragen.

  • Dateivorgänge können nur für einige Dateien aus der Ergebnismenge ausgeführt werden - dh nach Größe sortieren, einige große Dateien löschen, die nicht benötigt werden

Sergey
quelle