web-dev-qa-db-fra.com

Comment trouver récursivement le dernier fichier modifié dans un répertoire?

Il semble que ls ne trie pas les fichiers correctement lors d’un appel récursif:

ls -altR . | head -n 3

Comment trouver le dernier fichier modifié dans un répertoire (y compris les sous-répertoires)?

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

Pour un arbre énorme, il peut être difficile pour sort de tout garder en mémoire.

%T@ vous donne l'heure de modification comme un horodatage unix, sort -n trie numériquement, tail -1 prend la dernière ligne (horodatage le plus élevé), cut -f2 -d" " coupe le premier champ (l'horodatage) de la sortie.

Edit: Tout comme -printf est probablement uniquement GNU, l'utilisation ajreals de stat -c l'est aussi. Bien qu'il soit possible de faire la même chose sous BSD, les options de formatage sont différentes (-f "%m %N" semble-t-il)

Et j'ai raté le pluriel; si vous voulez plus que le dernier fichier, augmentez simplement l'argument tail.

321
plundra

Pour faire suite à @ plundra , voici la version BSD et OS X:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "
118
Emerson Farrugia

Au lieu de trier les résultats et de ne conserver que les derniers modifiés, vous pouvez utiliser awk pour n’imprimer que celui dont le temps de modification est le plus élevé (en temps unix):

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

Cela devrait être un moyen plus rapide de résoudre votre problème si le nombre de fichiers est suffisant.

J'ai utilisé le caractère NUL (c'est-à-dire '\ 0') car, théoriquement, un nom de fichier peut contenir n'importe quel caractère (y compris l'espace et la nouvelle ligne), à ​​l'exception de cela.

Si vous n'avez pas de tels noms de fichiers pathologiques dans votre système, vous pouvez également utiliser le caractère de nouvelle ligne:

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

De plus, cela fonctionne aussi dans mawk.

14
marco

J'ai eu du mal à trouver le dernier fichier modifié sous Solaris 10. Il n'y a pas d'option find et l'option printf et stat ne sont pas disponibles. J'ai découvert la solution suivante qui fonctionne bien pour moi:

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

Pour afficher également le nom du fichier, utilisez

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

Explication

  • find . -type f trouve et répertorie tous les fichiers
  • sed 's/.*/"&"/' encapsule le chemin d'accès entre guillemets pour gérer les espaces
  • xargs ls -E envoie le chemin cité à ls, l'option -E s'assure qu'un horodatage complet (format année-mois-jour heure-minute-secondes-nanosecondes) est renvoyé
  • awk '{ print $6," ",$7 }' extrait uniquement la date et l'heure
  • awk '{ print $6," ",$7," ",$9 }' extrait la date, l'heure et le nom du fichier
  • sort renvoie les fichiers triés par date
  • tail -1 renvoie uniquement le dernier fichier modifié
10
Florian Feldhaus

Cela semble bien fonctionner, même avec les sous-répertoires:

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

En cas de trop grand nombre de fichiers, affinez la recherche.

9
mgratia

Affiche le dernier fichier avec un horodatage lisible par l'homme:

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

Le résultat ressemble à ceci:

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

Pour afficher plus de fichiers, remplacez -n1 par un nombre plus élevé.

6

Cela donne une liste triée:

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

Inverser la commande en plaçant un '-r' dans la commande de tri. Si vous ne voulez que les noms de fichiers, insérez "awk '{print $ 11}' |" avant '| tête'

4
Karlo

Sous Ubuntu 13, ce qui suit fonctionne, peut-être un peu plus vite, car il inverse le tri et utilise "tête" au lieu de "queue", ce qui réduit le travail. Pour afficher les 11 fichiers les plus récents dans un arbre:

trouver . -type f -printf '% T @% p\n' | trier -n -r | tête -11 | cut -f2- -d "" | sed -e 's, ^./,' | xargs ls -U -l

Cela donne une liste complète de ls sans re-trier et omet le './' ennuyeux que 'trouver' met sur chaque nom de fichier.

Ou, en tant que fonction bash:

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
}

Néanmoins, la plupart du travail a été effectué avec la solution initiale de plundra. Merci beaucoup.

3
RickyS

Si exécuter stat sur chaque fichier individuellement est lent, vous pouvez utiliser xargs pour accélérer un peu les choses:

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

Cela modifie de manière récursive l'heure de modification de tous les répertoires du répertoire actuel vers le fichier le plus récent de chaque répertoire

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
2
rwhirn

J'utilise quelque chose de similaire tout le temps, ainsi que la liste des plus récents fichiers modifiés. Pour les grandes arborescences de répertoires, il peut être beaucoup plus rapide pour éviter le tri. Dans le cas du dernier fichier modifié le plus récent:

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

Sur un répertoire contenant 1,7 million de fichiers, j'obtiens le dernier en 3.4, soit 7,5 fois plus rapide que la solution 25.5 avec tri.

2
Pierre D

J'ai fait face au même problème. Je dois trouver le fichier le plus récent de manière récursive. Il a fallu environ 50 minutes pour trouver.

Voici un petit script pour le faire plus vite:

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

C'est une fonction récursive qui récupère l'élément modifié le plus récent d'un répertoire. Si cet élément est un répertoire, la fonction est appelée de manière récursive et recherche dans ce répertoire, etc.

2
AnatomicJC

Ce simple cli fonctionnera également:

ls -1t | head -1

Vous pouvez changer le -1 pour le nombre de fichiers que vous voulez lister

2
Ankit Zalani

La commande suivante a fonctionné sous Solaris:

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

Je trouve ce qui suit plus court et avec une sortie plus interprétable:

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

Étant donné la longueur fixe des dates-temps au format ISO normalisé, le tri lexicographique convient et nous n'avons pas besoin de l'option -n pour le tri.

Si vous souhaitez supprimer à nouveau les horodatages, vous pouvez utiliser:

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

Pour rechercher des fichiers dans/target_directory et tous ses sous-répertoires modifiés au cours des 60 dernières minutes:

$ find /target_directory -type f -mmin -60

Pour rechercher les derniers fichiers modifiés, triés dans l’ordre inverse de la date de mise à jour (c’est-à-dire les fichiers les plus récemment mis à jour en premier):

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

Ignorer les fichiers cachés - avec horodatage Nice et rapide

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

Résultat

Gère bien les espaces dans les noms de fichiers - pas que ceux-ci doivent être utilisés!

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

Plus

Plusfind à gogo en suivant le lien.

1
Serge Stroobandt

J'ai trouvé la commande ci-dessus utile, mais pour mon cas, j'avais besoin de connaître la date et l'heure du fichier. Un problème avec plusieurs fichiers contenant des espaces dans les noms .

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

J'ai écrit un paquet pypi/github pour cette question car j'avais également besoin d'une solution.

https://github.com/bucknerns/logtail

Installer:

pip install logtail

Usage: fichiers modifiés

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

Usage2: Ouvre le dernier fichier modifié dans l'éditeur

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

Je préfère celui-ci, il est plus court:

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