47 votes

Recherche du dernier fichier par date de modification

Si je veux trouver le dernier fichier (mtime) dans un (grand) répertoire contenant des sous-répertoires, comment dois-je procéder ?

De nombreux messages que j'ai trouvés suggèrent une variante de ls -lt | head (il est amusant de constater que de nombreuses personnes suggèrent ls -ltr | tail ce qui est la même chose mais moins efficace), ce qui est parfait à moins que vous n'ayez des sous-répertoires (c'est mon cas).

Mais vous pourriez aussi

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

qui fera certainement l'affaire pour autant de fichiers qu'il est possible de spécifier par une seule commande, c'est-à-dire si vous avez un fichier grand répertoire, -exec...\+ émettront des commandes distinctes ; par conséquent, chaque groupe sera trié par ls à l'intérieur d'elle-même, mais pas sur l'ensemble de l'ensemble ; la tête prendra donc la dernière entrée du premier lot.

Des réponses ?

61voto

enzotib Points 86709

Il n'est pas nécessaire de recourir à des commandes externes (telles que ls ) car find peut faire tout ce dont vous avez besoin par l'intermédiaire du -printf action :

find /path -printf '%T+ %p\n' | sort -r | head

10voto

WebDude Points 3326

J'ai eu un problème similaire aujourd'hui, mais je l'ai attaqué sans find . J'avais besoin de quelque chose de court que je pouvais écraser ssh pour obtenir le fichier le plus récemment édité dans mon répertoire personnel. C'est à peu près ce que j'ai trouvé :

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

En -p à l'option ls ajoute une barre oblique aux répertoires, l'option grep -v supprime les lignes se terminant par une barre oblique (c'est-à-dire tous les répertoires), et l'option head -1 limite la sortie à un seul fichier.

C'est beaucoup moins verbeux que d'utiliser find si tout ce que vous voulez obtenir est le nom du fichier.

4voto

DublinJimbo Points 314

Sur mon système, c'est plus rapide que printf Bien que je ne comprenne pas pourquoi

find /path -type f -exec stat -c "%y %n" {} + | sort -r | head

3voto

Prasanth S Points 1176

EDIT : Je pense que ce post n'est pas "pas particulièrement utile" comme je le pensais. Il s'agit d'une solution très rapide qui se contente de garder la trace du fichier le plus récemment modifié (au lieu de trier toute la liste des fichiers) :

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 ' '

Réparti sur plusieurs lignes pour plus de clarté, il se présente comme suit :

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 ' '

Fin de l'EDIT


Il ne s'agit pas d'un article particulièrement utile, mais comme "arrange" parlait de vitesse, j'ai pensé le partager.

Les solutions d'arrange et d'enzotib consistent à lister tous les fichiers du répertoire avec leurs mtimes, puis à les trier. Comme vous le savez, le tri n'est pas nécessaire pour trouver le maximum. Trouver le maximum peut être fait en temps linéaire mais le tri prend n log(n) temps [je sais que la différence n'est pas énorme, mais quand même ;)]. Je n'arrive pas à trouver une façon élégante d'implémenter cela. [EDIT : Une implémentation rapide et soignée (bien qu'elle ait l'air sale) est fournie ci-dessus].

Prochaine meilleure solution - Pour trouver le fichier le plus récemment édité dans un répertoire, recherchez récursivement le fichier le plus récemment édité dans chaque sous-répertoire de niveau 1. Ce fichier représente le sous-répertoire. Triez ensuite les fichiers de niveau 1 avec les représentants des sous-répertoires de niveau 1. Si le nombre de fichiers de niveau 1 et de sous-répertoires de chaque répertoire est presque constant, ce processus devrait s'échelonner linéairement avec le nombre total de fichiers.

Voici ce que j'ai trouvé pour mettre cela en œuvre :

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 .

Je l'ai lancé et j'ai obtenu un grand nombre de find: findrecent: No such file or directory erreurs. Raison : -exec de find s'exécute dans un Shell différent. J'ai essayé de définir findrecent dans .bashrc, .xsessionrc mais cela n'a pas aidé [j'apprécierais de l'aide ici]. En fin de compte, j'ai dû mettre

#!/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;

dans un script appelé findrecent dans mon PATH et de l'exécuter.

J'ai exécuté ce programme, qui n'a cessé d'attendre, sans résultat. Pour être sûr de ne pas avoir affaire à des boucles infinies, j'ai modifié le fichier en

#!/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;

et a réessayé. Cela a fonctionné - mais a pris 1 minute 35 secondes sur mon dossier personnel - les solutions d'arrange et d'enzotib ont pris respectivement 1,69 et 1,95 secondes !

Voilà pour la supériorité de O(n) sur O(n log (n)) ! Maudit soit le surcoût des appels de fonction ! [Ou plutôt script surcharge d'appels de fonctions].

Mais ce script s'adapte mieux que les solutions précédentes et je parie qu'il fonctionnera plus vite qu'elles sur la banque de mémoire de Google ;D

3voto

Raj J Points 677

Utilisation perl en conjonction avec find :

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

Vous obtenez le nom du fichier dont l'époque est la plus grande == dernier fichier modifié.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X