Wie finde ich rekursiv die zuletzt geänderte Datei in einem Verzeichnis?

Antworten:

357
find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "

Für einen riesigen Baum könnte es schwierig sein sort, alles im Gedächtnis zu behalten.

%T@gibt Ihnen die Änderungszeit wie ein Unix-Zeitstempel, sort -nsortiert numerisch, tail -1nimmt die letzte Zeile (höchster Zeitstempel) und cut -f2 -d" "schneidet das erste Feld (den Zeitstempel) von der Ausgabe ab.

Bearbeiten: Genau wie -printfes wahrscheinlich nur GNU ist, ist auch Ajreals Verwendung von stat -c. Obwohl es möglich ist, dasselbe mit BSD zu tun, sind die Formatierungsoptionen unterschiedlich (wie -f "%m %N"es scheint).

Und ich habe den Teil des Plural verpasst; Wenn Sie mehr als die neueste Datei möchten , erhöhen Sie einfach das Argument tail.

Plundra
quelle
7
Wenn die Reihenfolge wichtig ist, können Sie die Verwendung sort -rn | head -3anstelle von wechseln sort -n | tail -3. Eine Version gibt die Dateien vom ältesten zum neuesten, während die andere vom neuesten zum ältesten wechselt.
Don Faulkner
3
Ich hatte ein riesiges Verzeichnis (ungefähr zehntausend kleine Dateien) und war besorgt über die Leistung, aber ... dieser Befehl wurde in weniger als einer Sekunde ausgeführt! Super, vielen Dank !!! :-)
lucaferrario
2
"Für einen riesigen Baum könnte es schwierig sein, alles in Erinnerung zu behalten." sorterstellt /tmpnach Bedarf temporäre Dateien (in ), daher denke ich nicht, dass dies ein Problem ist.
Vladimir Panteleev
1
Ändern Sie es an: -printf '%T@ %Tb %Td %TY %p\n'geben Ihnen einen Datumsstempel (falls erforderlich) (ähnlich ls)
bshea
1
Ich finde folgendes kürzer und mit besser interpretierbarer Ausgabe:find . -type f -printf '%TF %TT %p\n' | sort | tail -1
7.
129

Nach der Antwort von @ plundra finden Sie hier die BSD- und OS X-Version:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "
Emerson Farrugia
quelle
1
findUnterstützt das BSD / OS X +statt \;? Denn das macht dasselbe (mehrere Dateien als Parameter übergeben), ohne die -print0 | xargs -0Pipe.
DevSolar
Was tun, wenn die letzten 5 oder n Dateien in absteigender Reihenfolge geändert werden sollen?
Khunshan
@ Khunshan ändern die head -1zuhead -5
Emerson Farrugia
20

Anstatt die Ergebnisse zu sortieren und nur die zuletzt geänderten beizubehalten, können Sie mit awk nur das Ergebnis mit der größten Änderungszeit (in Unix-Zeit) drucken:

find . -type f -printf "%T@\0%p\0" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\0'

Dies sollte ein schnellerer Weg sein, um Ihr Problem zu lösen, wenn die Anzahl der Dateien groß genug ist.

Ich habe das NUL-Zeichen (dh '\ 0') verwendet, da ein Dateiname theoretisch jedes beliebige Zeichen (einschließlich Leerzeichen und Zeilenumbruch) enthalten kann.

Wenn Sie keine solchen pathologischen Dateinamen in Ihrem System haben, können Sie auch das Zeilenumbruchzeichen verwenden:

find . -type f -printf "%T@\n%p\n" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\n'

Darüber hinaus funktioniert dies auch in Mawk.

marco
quelle
Dies könnte leicht angepasst werden, um die drei neuesten zu halten.
Bis auf weiteres angehalten.
1
Dies funktioniert nicht mit mawkder Debian-Standardalternative.
Januar
Nein, aber in diesem Fall können Sie das Zeilenumbruchzeichen verwenden, wenn es Sie nicht stört;)
marco
10

Ich hatte Probleme, die zuletzt geänderte Datei unter Solaris 10 zu finden. Es findgibt keine printfOption und sie statist nicht verfügbar. Ich habe die folgende Lösung gefunden, die für mich gut funktioniert:

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7 }' | sort | tail -1

Um auch den Dateinamen anzuzeigen, verwenden Sie

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7," ",$9 }' | sort | tail -1

Erläuterung

  • find . -type f findet und listet alle Dateien auf
  • sed 's/.*/"&"/' Umschließt den Pfadnamen in Anführungszeichen, um Leerzeichen zu verarbeiten
  • xargs ls -EWenn der angegebene Pfad an gesendet wird, lsstellt die -EOption sicher, dass ein vollständiger Zeitstempel (Format Jahr-Monat-Tag Stunde-Minute-Sekunden-Nanosekunden ) zurückgegeben wird
  • awk '{ print $6," ",$7 }' extrahiert nur Datum und Uhrzeit
  • awk '{ print $6," ",$7," ",$9 }' extrahiert Datum, Uhrzeit und Dateinamen
  • sort Gibt die nach Datum sortierten Dateien zurück
  • tail -1 Gibt nur die zuletzt geänderte Datei zurück
Florian Feldhaus
quelle
9

Dies scheint auch mit Unterverzeichnissen gut zu funktionieren:

find . -type f | xargs ls -ltr | tail -n 1

Bei zu vielen Dateien verfeinern Sie den Fund.

Mgratia
quelle
1
Die -lOption zu lserscheint unnötig. Scheint einfach -trausreichend.
Acumenus
6
Dies scheint nach Verzeichnis zu sortieren, so dass nicht unbedingt die neueste Datei
angezeigt wird
1
Falls die Dateipfade Leerzeichen enthalten, tun Sie find . -type f -print0 | xargs -0 ls -ltr | tail -n 1
Folgendes
Dies findet nicht die neuesten Dateien für mich.
K.-Michael Aye
1
Denken Sie, dass dies bricht, wenn Leerzeichen in Dateinamen vorhanden sind
Wafer innerhalb des
7

Zeigt die neueste Datei mit lesbarem Zeitstempel an:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM: %Tz %p\n'| sort -n | tail -n1

Ergebnis sieht so aus:

2015-10-06 11:30: +0200 ./foo/bar.txt

Um mehr Dateien anzuzeigen, ersetzen Sie diese -n1durch eine höhere Nummer

Fabian Schmengler
quelle
5

Ich verwende ständig etwas Ähnliches sowie die Top-K-Liste der zuletzt geänderten Dateien. Bei großen Verzeichnisbäumen kann es viel schneller sein, eine Sortierung zu vermeiden . Im Fall der zuletzt geänderten Top-1-Datei:

find . -type f -printf '%T@ %p\n' | perl -ne '@a=split(/\s+/, $_, 2); ($t,$f)=@a if $a[0]>$t; print $f if eof()'

In einem Verzeichnis mit 1,7 Millionen Dateien erhalte ich das neueste in 3.4s, eine Beschleunigung von 7.5x gegenüber der 25.5s-Lösung mit sort.

Pierre D.
quelle
Sehr cool: Ich habe gerade den letzten Druck mit: system ("ls -l $ f") if eof () ausgetauscht, um das Datum auch schön zu sehen.
Martin T.
@ MartinT. : toll, und du bist willkommen. Es ist seltsam für mich, dass Menschen diesen Instinkt haben, Dinge zu sortieren (O (n log n)), wenn eine O (n) -Methode verfügbar ist. Dies scheint die einzige Antwort zu sein, die eine Sortierung vermeidet. Übrigens ist das Ziel des von mir vorgeschlagenen Befehls nur, den Pfad der neuesten Datei zu finden. Sie können den Befehl in Ihrer Shell als Alias ​​verwenden (z. B. als lastfile) und dann mit dem Ergebnis tun, was Sie möchten, z. B. ls -l $(lastfile .)oder open $(lastfile .)(auf einem Mac) usw.
Pierre D
Oh, ich stehe korrigiert da: Ich sehe unten eine andere Antwort (@marco). +1.
Pierre D
4

Dies ergibt eine sortierte Liste:

find . -type f -ls 2>/dev/null | sort -M -k8,10 | head -n5

Kehren Sie die Reihenfolge um, indem Sie im Sortierbefehl ein '-r' einfügen. Wenn Sie nur Dateinamen möchten, geben Sie "awk '{print $ 11}' |" ein. vor '| Kopf'

Karlo
quelle
3

Unter Ubuntu 13 funktioniert dies im Folgenden möglicherweise etwas schneller, da die Sortierung umgekehrt wird und "Kopf" anstelle von "Schwanz" verwendet wird, wodurch die Arbeit reduziert wird. So zeigen Sie die 11 neuesten Dateien in einem Baum an:

finden . -Typ f -printf '% T @% p \ n' | sort -n -r | Kopf -11 | cut -f2- -d "" | sed -e 's, ^. / ,,' | xargs ls -U -l

Dies ergibt eine vollständige ls-Liste ohne erneutes Sortieren und lässt das nervige './' weg, das 'find' auf jeden Dateinamen setzt.

Oder als Bash-Funktion:

treecent () {
  local numl
  if [[ 0 -eq $# ]] ; then
    numl=11   # Or whatever default you want.
  else
    numl=$1
  fi
  find . -type f -printf '%T@ %p\n' | sort -n -r | head -${numl} |  cut -f2- -d" " | sed -e 's,^\./,,' | xargs ls -U -l
}

Der größte Teil der Arbeit wurde jedoch mit der ursprünglichen Lösung von plundra erledigt. Danke plundra.

RickyS
quelle
3

Ich stand vor dem gleichen Problem. Ich muss die neueste Datei rekursiv finden. Die Suche dauerte ungefähr 50 Minuten.

Hier ist ein kleines Skript, um es schneller zu machen:

#!/bin/sh

CURRENT_DIR='.'

zob () {
    FILE=$(ls -Art1 ${CURRENT_DIR} | tail -n 1)
    if [ ! -f ${FILE} ]; then
        CURRENT_DIR="${CURRENT_DIR}/${FILE}"
        zob
    fi
    echo $FILE
    exit
}
zob

Es ist eine rekursive Funktion, die das zuletzt geänderte Element eines Verzeichnisses abruft. Wenn es sich bei diesem Element um ein Verzeichnis handelt, wird die Funktion rekursiv aufgerufen und in diesem Verzeichnis usw. gesucht.

AnatomicJC
quelle
3

Ich finde folgendes kürzer und mit besser interpretierbarer Ausgabe:

find . -type f -printf '%TF %TT %p\n' | sort | tail -1

Angesichts der festen Länge der standardisierten Datumszeiten im ISO-Format ist die lexikografische Sortierung in Ordnung und wir benötigen keine -nOption für die Sortierung.

Wenn Sie die Zeitstempel wieder entfernen möchten, können Sie Folgendes verwenden:

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '
snth
quelle
2

Wenn das Ausführen statjeder einzelnen Datei zu langsam ist, können Sie die xargsDinge etwas beschleunigen:

find . -type f -print0 | xargs -0 stat -f "%m %N" | sort -n | tail -1 | cut -f2- -d" " 
Mattias Wadman
quelle
2

Dadurch wird die Änderungszeit aller Verzeichnisse im aktuellen Verzeichnis rekursiv in die neueste Datei in jedem Verzeichnis geändert:

for dir in */; do find $dir -type f -printf '%T@ "%p"\n' | sort -n | tail -1 | cut -f2- -d" " | xargs -I {} touch -r {} $dir; done
rwhirn
quelle
1
Es bricht schlecht, wenn Verzeichnisse Leerzeichen enthalten - IFS muss gesetzt und in Anführungszeichen gesetzt werden: IFS = $ '\ n'; für dir in $ (find ./ -type d); Echo "$ dir"; finde "$ dir" -Typ f -printf '% T @ "% p" \ n' | sort -n | Schwanz -1 | cut -f2- -d "" | xargs -I {} touch -r {} "$ dir"; getan;
Andy Lee Robinson
2

Diese einfache Cli wird auch funktionieren:

ls -1t | head -1

Sie können -1 in die Anzahl der Dateien ändern, die Sie auflisten möchten

Ankit Zalani
quelle
10
Nein, wird es nicht, da es nicht rekursiv ist.
Arataj
1

Ich fand den obigen Befehl nützlich, aber für meinen Fall musste ich auch das Datum und die Uhrzeit der Datei sehen. Ich hatte ein Problem mit mehreren Dateien, deren Namen Leerzeichen enthalten. Hier ist meine Arbeitslösung.

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | sed 's/.*/"&"/' | xargs ls -l
Roger Cable
quelle
1

Der folgende Befehl funktionierte unter Solaris:

find . -name "*zip" -type f | xargs ls -ltr | tail -1 
RahulM
quelle
1

Versteckte Dateien ignorieren - mit schönem und schnellem Zeitstempel

$ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10

Ergebnis

Behandelt Leerzeichen in Dateinamen gut - nicht, dass diese verwendet werden sollten!

2017.01.25 18h23 Wed ./indenting/Shifting blocks visually.mht
2016.12.11 12h33 Sun ./tabs/Converting tabs to spaces.mht
2016.12.02 01h46 Fri ./advocacy/2016.Vim or Emacs - Which text editor do you prefer?.mht
2016.11.09 17h05 Wed ./Word count - Vim Tips Wiki.mht

Mehr

Mehr in find Hülle und Fülle folgen Sie dem Link.

Serge Stroobandt
quelle
1

So suchen Sie nach Dateien in / target_directory und allen Unterverzeichnissen, die in den letzten 60 Minuten geändert wurden:

$ find /target_directory -type f -mmin -60

So finden Sie die zuletzt geänderten Dateien in umgekehrter Reihenfolge der Aktualisierungszeit (dh zuerst die zuletzt aktualisierten Dateien):

$ find /etc -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r
akash
quelle
0

Ich bevorzuge dieses, es ist kürzer:

find . -type f -print0|xargs -0 ls -drt|tail -n 1
user3295940
quelle
0

Ich habe ein Pypi / Github-Paket für diese Frage geschrieben, weil ich auch eine Lösung brauchte.

https://github.com/bucknerns/logtail

Installieren:

pip install logtail

Verwendung: Schwänze geänderte Dateien

logtail <log dir> [<glob match: default=*.log>]

Verwendung2: Öffnet die zuletzt geänderte Datei im Editor

editlatest <log dir> [<glob match: default=*.log>]
Nathan Buckner
quelle