Trouver le dernier fichier par date de modification


39

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

Beaucoup de messages que j'ai trouvés suggèrent une variation de ls -lt | head(curieusement, beaucoup suggèrent ls -ltr | tailce qui est le même mais moins efficace) ce qui est bien à moins que vous n'ayez des sous-répertoires (moi aussi).

Là encore, vous pourriez

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

ce qui fera certainement l'affaire pour autant de fichiers pouvant être spécifiés par une commande, c'est-à-dire que si vous avez un grand répertoire, -exec...\+émettra des commandes séparées; par conséquent, chaque groupe sera trié en son lssein, mais pas sur l'ensemble total; la tête récupérera donc la dernière entrée du premier lot.

Des réponses?


Par ailleurs, vous n'avez pas besoin de toutes ces barres obliques inverses.
enzotib

@enzotib: vous faites ( \ + ), sinon vous obtenezfind: missing argument to '-exec'
arranger le

@arrange: Je n'ai pas cette erreur, car cela +n'a pas de sens bash, donc pas besoin de l'échapper.
enzotib

@enzotib: tu as raison, mon erreur, désolée
arranger le

Réponses:


46

Vous n'avez pas besoin de recourir à des commandes externes (comme ls) car vous findpouvez faire tout ce dont vous avez besoin grâce à l' -printfaction:

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

1
Oui, je suis venu avec find . -type f -exec stat --format=%y \{\} \+ | sort -r | head -n1mais votre solution est de loin plus propre!
Rich

3
Ajouter | cut -d ' ' -f2pour obtenir le nom de fichier uniquement
qwr

Vous pouvez également sélectionner la sortie headpour inclure un certain nombre de lignes. Je n'avais besoin que de la première ligne, alors j'ai utiliséhead -n 1
Timmah

8

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 sshpour retourner le dernier fichier édité dans mon répertoire personnel. C’est à peu près ce que j’ai trouvé:

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

L' -poption permettant d' lsajouter une barre oblique grep -vfinale aux répertoires, supprime les lignes se terminant par une barre oblique (tous les répertoires) et head -1limite la sortie à un seul fichier.

C'est beaucoup moins bavard que d'utiliser findsi tout ce que vous voulez retourner est le nom du fichier.


Cela ne gère pas les sous-répertoires.
Clément

4

Ceci est sur mon système plus rapide que printf, bien que je ne comprenne pas pourquoi

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

Je confirme, c'est plus rapide.
enzotib

Un autre point, ... | sort -r | head -n1 | cut -d " " -f 4-si vous voulez obtenir le nom de fichier uniquement.
林果皞

Je viens de trouver sort -rsera faux s'il existe un nom de fichier sur plusieurs lignes.
林果皞

2

EDIT: Je suppose que ce post n'est pas "pas particulièrement utile" comme je le pensais. C'est une solution très rapide qui ne fait que garder trace du dernier fichier modifié (au lieu de trier la liste complète 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


Ce message n’est pas particulièrement utile, mais comme «organiser» parle de vitesse, j’ai pensé partager cela.

Les solutions de arrange et de enzotib impliquent de lister tous les fichiers du répertoire avec leurs heures, puis de 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 grande, mais quand même;)]. Je ne peux pas penser à un moyen élégant de mettre cela en œuvre. [EDIT: Une mise en œuvre soignée (bien que sale) et rapide fournie ci-dessus.]

Meilleure chose à faire - Pour rechercher 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. Laissez ce fichier représenter le sous-répertoire. Maintenant, triez 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, le processus doit évoluer de manière linéaire avec le nombre total de fichiers.

Voici ce que je suis venu avec pour implémenter ceci:

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 .

J'ai couru cela et j'ai eu un tas d' find: findrecent: No such file or directoryerreurs. Raison: -exec de la recherche 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 l'aide ici]. Finalement, j'ai eu recours à

#!/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é findrecentdans mon PATH, puis en l'exécutant.

J'ai couru ceci, continuais d'attendre et d'attendre sans sortie. Juste pour être sûr que je n'avais pas 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 essayé à nouveau. Cela a fonctionné - mais cela a pris 1 minute 35 secondes sur mon homefolder - les solutions d'Arange et enzotib ont pris respectivement 1,69 et 1,95 secondes!

Voilà pour la supériorité de O (n) sur O (n log (n))! Bon sang, vous appelez des frais généraux [Ou plutôt appel overhead]

Mais ce script est plus performant que les solutions précédentes et je parie qu'il s'exécutera plus rapidement que sur la mémoire de google; D


2

Utiliser perlen conjonctin 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 avec la plus grande époque == dernier fichier modifié.


1

Ce n’est pas aussi à la mode, mais il est également possible d’atteindre cet objectif avec Midnight Commander : rechercher *, regrouper le résultat, trier par date de modification dans l’ordre inverse.

Évidemment, c'est un peu plus lent que find- mon répertoire personnel, contenant 922 000 fichiers, a été trié mcen presque 14 minutes alors qu'il en a findutilisé moins de cinq -, mais il y a quelques avantages:

  • Je passerais probablement plus de temps que la différence de 9 minutes à inventer une invocation de découverte appropriée :)

  • moins de risque d'erreur (j'ai oublié de spécifier -r pour le tri, etc. - recommencez)

  • il est possible de jouer avec le jeu de résultats en modifiant l'ordre de tri, etc. - sans interroger à nouveau les fichiers.

  • possible d’effectuer des opérations sur certains fichiers du jeu de résultats - c’est-à-dire trier par taille, supprimer quelques fichiers volumineux inutiles

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.