it-swarm.com.de

Wie kann man rekursiv die zuletzt geänderten Dateien in einem Verzeichnis mit Unterverzeichnissen und Zeiten finden und auflisten?

  • Betriebssystem: Linux

  • Dateisystemtyp: ext3

  • Bevorzugte Lösung: Bash (Script/Oneliner), Ruby, Python

Ich habe mehrere Verzeichnisse mit mehreren Unterverzeichnissen und Dateien in ihnen. Ich muss eine Liste aller dieser Verzeichnisse erstellen, die so aufgebaut ist, dass jedes Verzeichnis der ersten Ebene neben dem Datum und der Uhrzeit der zuletzt erstellten/geänderten Datei darin aufgeführt wird.

Zur Verdeutlichung sollte der Zeitstempel neben dem Verzeichnisnamen der ersten Ebene angezeigt werden, wenn ich eine Datei berühre oder deren Inhalt einige Unterverzeichnisebenen tiefer ändere. Angenommen, ich habe ein Verzeichnis wie folgt aufgebaut:

./alfa/beta/gamma/example.txt

und ich ändere den Inhalt der Datei example.txt, ich brauche diese Zeit neben dem Verzeichnis der ersten Ebene alfa in lesbarer Form, nicht Epoche. Ich habe einige Dinge mit find, xargs, sort und ähnlichem ausprobiert, aber ich kann das Problem nicht umgehen, dass sich der Zeitstempel des Dateisystems von 'alfa' beim Erstellen/Ändern von Dateien nicht ändert ein paar Ebenen tiefer.

377
fredrik

Probier diese:

#!/bin/bash
find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

Führen Sie es mit dem Pfad zu dem Verzeichnis aus, in dem das rekursive Scannen beginnen soll (es unterstützt Dateinamen mit Leerzeichen).

Wenn viele Dateien vorhanden sind, kann es eine Weile dauern, bis etwas zurückgegeben wird. Die Leistung kann verbessert werden, wenn stattdessen xargs verwendet wird:

#!/bin/bash
find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head

das ist ein bisschen schneller.

441
Heppo

So finden Sie alle Dateien, deren Dateistatus zuletzt geändert wurde N vor Minuten:

find -cmin -N

zum Beispiel:

find -cmin -5

176
iman

GNU Find (siehe man find) verfügt über einen -printf -Parameter zur Angabe der EPOC-Zeit und des relativen Pfadnamens.

redhat> find . -type f -printf '%[email protected] %P\n' | sort -n | awk '{print $2}'
38
user2570243

Ich habe die großartige Antwort von halo auf diesen Einzeiler gekürzt

stat --printf="%y %n\n" $(ls -tr $(find * -type f))

pdated: Wenn Dateinamen Leerzeichen enthalten, können Sie diese Änderung verwenden

OFS="$IFS";IFS=$'\n';stat --printf="%y %n\n" $(ls -tr $(find . -type f));IFS="$OFS";
34
slashdottir

Versuche dies

#!/bin/bash
stat --format %y $(ls -t $(find alfa/ -type f) | head -n 1)

Es verwendet find, um alle Dateien aus dem Verzeichnis zu sammeln, ls, um sie nach Änderungsdatum sortiert aufzulisten, head, um die erste Datei auszuwählen und schließlich stat, um die Zeit in anzuzeigen ein schönes Format.

Derzeit ist es nicht sicher für Dateien mit Leerzeichen oder anderen Sonderzeichen im Namen. Schreiben Sie eine Empfehlung, wenn diese noch nicht Ihren Anforderungen entspricht.

15
Daniel Böhmer

Dieser Befehl funktioniert unter Mac OS X:

find "$1" -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head

Verwenden Sie unter Linux, wie im Original-Poster gefordert, stat anstelle von gstat.

Diese Antwort ist natürlich ser37078 s herausragende Lösung, die vom Kommentar zur vollständigen Antwort hochgestuft wurde. Ich habe CharlesB s Einblick in die Verwendung von gstat unter Mac OS X beigemischt. Ich habe coreutils von - MacPorts statt Homebrew übrigens.

Und so habe ich das in einen einfachen Befehl ~/bin/ls-recent.sh zur Wiederverwendung gepackt:

#!/bin/bash
# ls-recent: list files in a dir tree, most recently modified first
#
# Usage: ls-recent path [-10 | more]
# 
# Where "path" is a path to target directory, "-10" is any arg to pass
# to "head" to limit the number of entries, and "more" is a special arg
# in place of "-10" which calls the pager "more" instead of "head".
if [ "more" = "$2" ]; then
   H=more; N=''
else
   H=head; N=$2
fi

find "$1" -type f -print0 |xargs -0 gstat --format '%Y :%y %n' \
    |sort -nr |cut -d: -f2- |$H $N
10
Jim DeLaHunt

Sowohl die Perl- als auch die Python - Lösung in diesem Beitrag haben mir geholfen, dieses Problem unter Mac OS X zu lösen: https://unix.stackexchange.com/questions/9247/how-to-list-files-sorted -bei-Änderung-Datum-rekursiv-kein-stat-Befehl-verfügbar .

Zitat aus dem Beitrag:

Perl:

find . -type f -print |
Perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="\n";
        print sort {$_{$b} <=> $_{$a}} keys %_;  # print by decreasing age
    }'

Python:

find . -type f -print |
python -c 'import os, sys; times = {}
for f in sys.stdin.readlines(): f = f[0:-1]; times[f] = os.stat(f).st_mtime
for f in sorted(times.iterkeys(), key=lambda f:times[f]): print f'
5
William Niu

Ich zeige dies für die späteste Zugriffszeit. Sie können dies leicht ändern, um die späteste Änderungszeit zu erreichen.

Hierfür gibt es zwei Möglichkeiten:


1) Wenn Sie eine globale Sortierung vermeiden möchten, die bei zig Millionen Dateien teuer sein kann, können Sie Folgendes tun: (Positionieren Sie sich im Stammverzeichnis des Verzeichnisses, in dem die Suche beginnen soll.)

linux> touch -d @0 /tmp/a;
linux> find . -type f -exec tcsh -f -c test `stat --printf="%X" {}` -gt  `stat --printf="%X" /tmp/a`  ; -exec tcsh -f -c touch -a -r {} /tmp/a ; -print 

Die obige Methode druckt Dateinamen mit einer immer neueren Zugriffszeit, und die zuletzt gedruckte Datei ist die Datei mit der neuesten Zugriffszeit. Sie können die letzte Zugriffszeit natürlich mit "tail -1" abrufen.


2) Sie können den Namen, die Zugriffszeit aller Dateien in Ihrem Unterverzeichnis rekursiv drucken lassen und dann nach Zugriffszeit und dem Ende den größten Eintrag sortieren:

linux> \find . -type f -exec stat --printf="%X  %n\n" {} \; | \sort -n | tail -1

Und da hast du es ...

3
Sean

Versteckte Dateien ignorieren - mit schönem & schnellem Zeitstempel

Behandelt Leerzeichen in Dateinamen gut - nicht, dass Sie diese verwenden sollten!

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

2017.01.28 07h00 Sat ./recent
2017.01.21 10h49 Sat ./hgb
2017.01.16 07h44 Mon ./swx
2017.01.10 18h24 Tue ./update-stations
2017.01.09 10h38 Mon ./stations.json

Mehr find in Hülle und Fülle finden Sie unter folgendem Link.

3

Ich habe diesen Alias ​​in meinem .profil, den ich ziemlich oft benutze

$ alias | grep xlogs
xlogs='Sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | Sudo xargs ls -ltr --color | less -R'

Es macht also das, wonach Sie suchen (mit der Ausnahme, dass es Datum/Uhrzeit nicht in mehreren Ebenen ändert) - sucht nach den neuesten Dateien (* .log- und * .trc-Dateien in diesem Fall); Außerdem findet es nur Dateien, die am letzten Tag geändert wurden, und sortiert sie dann nach Zeit und leitet die Ausgabe durch weniger:

Sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | Sudo xargs ls -ltr --color | less -R

ps. Beachten Sie, dass ich auf einigen Servern kein Root-Verzeichnis habe, aber immer Sudo, sodass Sie dieses Teil möglicherweise nicht benötigen.

3
Tagar

Hier ist eine Version, die mit Dateinamen funktioniert, die auch Leerzeichen, Zeilenumbrüche und Glob-Zeichen enthalten können:

find . -type f -printf "%[email protected] %p\0" | sort -zk1nr
  • find ... -printf druckt die Dateimodifikation (Epochenwert), gefolgt von einem Leerzeichen und \0 abgeschlossenen Dateinamen.
  • sort -zk1nr liest NUL terminierte Daten und sortiert sie umgekehrt numerisch

Da die Frage mit Linux markiert ist, gehe ich davon aus, dass gnu -Utils verfügbar sind.

Du kannst oben pfeifen mit:

xargs -0 printf "%s\n"

zum Drucken von Änderungszeitpunkten und Dateinamen, sortiert nach Änderungszeitpunkten (neueste zuerst), die durch Zeilenumbrüche abgeschlossen werden.

1
anubhava

Schnelle Bash-Funktion:

# findLatestModifiedFiles(directory, [max=10, [format="%Td %Tb %TY, %TT"]])
function findLatestModifiedFiles() {
    local d="${1:-.}"
    local m="${2:-10}"
    local f="${3:-%Td %Tb %TY, %TT}"

    find "$d" -type f -printf "%[email protected] :$f %p\n" | sort -nr | cut -d: -f2- | head -n"$m"
}

Suchen Sie die zuletzt geänderte Datei in einem Verzeichnis:

findLatestModifiedFiles "/home/jason/" 1

Sie können auch Ihr eigenes Datums-/Uhrzeitformat als drittes Argument angeben.

1
Jason Larke

Das Folgende gibt eine Zeichenfolge des Zeitstempels und den Namen der Datei mit dem neuesten Zeitstempel zurück:

find $Directory -type f -printf "%TY-%Tm-%Td-%TH-%TM-%TS %p\n" | sed -r 's/([[:digit:]]{2})\.([[:digit:]]{2,})/\1-\2/' |     sort --field-separator='-' -nrk1 -nrk2 -nrk3 -nrk4 -nrk5 -nrk6 -nrk7 | head -n 1

Ergebnis zu einer Ausgabe des Formulars: <yy-mm-dd-hh-mm-ss.nanosec> <filename>

1
mark_infinite

Sie können den Befehl printf zum Suchen verwenden

Die letzte Zugriffszeit von% Ak File in dem von k angegebenen Format, bei dem es sich entweder um die Funktion @' or a directive for the C strftime handelt. Die möglichen Werte für k sind unten aufgeführt; Einige von ihnen sind möglicherweise nicht auf allen Systemen verfügbar, da sich die Arbeitszeiten der Systeme unterscheiden.

0
graugans

Das benutze ich (sehr effizient):

function find_last () { find "${1:-.}" -type f -printf '%TY-%Tm-%Td %TH:%TM %P\n' 2>/dev/null | sort | tail -n "${2:-10}" }

PROS:

  • es werden nur 3 Prozesse erzeugt

VERWENDUNGSZWECK:

find_last [dir [number]]

wo:

  • dir - ein zu durchsuchendes Verzeichnis [aktuelles Verzeichnis]
  • number - Anzahl der neuesten anzuzeigenden Dateien [10]

Die Ausgabe für find_last /etc 4 sieht folgendermaßen aus:

2019-07-09 12:12 cups/printers.conf
2019-07-09 14:20 salt/minion.d/_schedule.conf
2019-07-09 14:31 network/interfaces
2019-07-09 14:41 environment
0
Seweryn Niemiec

Dies könnte auch mit einer rekursiven Funktion in Bash geschehen

Sei F eine Funktion, die die Zeit der Datei anzeigt, die lexikographisch sortierbar sein muss. JJJJ-MM-TT usw. (os-abhängig?)

F(){ stat --format %y "$1";}                # Linux
F(){ ls -E "$1"|awk '{print$6" "$7}';}      # SunOS: maybe this could be done easier

R die rekursive Funktion, die Verzeichnisse durchläuft

R(){ local f;for f in "$1"/*;do [ -d "$f" ]&&R $f||F "$f";done;}

Und schlussendlich

for f in *;do [ -d "$f" ]&&echo `R "$f"|sort|tail -1`" $f";done
0

Verwenden Sie diese Option für die einfache Ausgabe von ls. Es gibt keine Argumentliste, daher kann es nicht zu lang werden:

find . | while read FILE;do ls -d -l "$FILE";done

Und mit cut nur für die Daten, Zeiten und Namen:

find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5

EDIT: Ich habe gerade bemerkt, dass die aktuelle Top-Antwort nach Änderungsdatum sortiert ist. Mit dem zweiten Beispiel ist das genauso einfach, da das Änderungsdatum in jeder Zeile an erster Stelle steht - setzen Sie eine Sortierung auf das Ende:

find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5 | sort
0
Izkata