2011-06-07 18:23:57 +0000 2011-06-07 18:23:57 +0000
152
152

Unix/Linux trouver et trier par date de modification

Comment puis-je faire un simple find qui ordonnerait les résultats selon la dernière modification ?

Voici le find actuel que j'utilise (je fais un escape shell en PHP, c'est donc le raisonnement des variables) :

find '$dir' -name '$str'\* -print | head -10

Comment puis-je faire en sorte que la recherche soit ordonnée selon la dernière modification ? (Notez que je ne veux pas qu'il trie “après” la recherche, mais qu'il trouve plutôt les résultats en fonction de ce qui a été modifié le plus récemment).

Réponses (17)

168
168
168
2013-02-05 13:31:01 +0000

Utilisez ceci :

find . -printf "%T@ %Tc %p\n" | sort -n

printf arguments de man find :

  • %Tk : Heure de la dernière modification du fichier dans le format spécifié par k.

  • @ : secondes depuis le 1er janvier 1970, 00:00 GMT, avec partie fractionnaire.

  • c : date et heure de la locale (Sat Nov 04 12:02:33 EST 1989).

  • %p : Nom du fichier.

85
85
85
2011-06-07 18:39:34 +0000

La méthode la plus simple est d'utiliser zsh, grâce à ses glob qualifiers .

print -lr -- $dir/**/$str*(om[1,10])

Si vous avez GNU find, faites-lui imprimer les heures de modification des fichiers et triez-les en fonction de cela.

find -type f -printf '%T@ %p```
find -type f -printf '%T@ %p\n' |
sort -k 1nr |
sed 's/^[^]* //' | head -n 10
```' |
sort -zk 1nr |
sed -z 's/^[^]* //' | tr '```
find . -type f -print |
perl -l -ne '
    $_{$_} = -M; # store file age (mtime - now)
    END {
        $,="\n";
        @sorted = sort {$_{$a} <=> $_{$b}} keys %_; # sort by increasing age
        print @sorted[0..9];
    }'
```' '\n' | head -n 10

Si vous avez GNU find mais pas d'autres utilitaires GNU, utilisez les nouvelles lignes comme séparateurs au lieu des zéros ; vous perdrez le support des noms de fichiers contenant des nouvelles lignes.

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], reverse=True))[:10]: print f'

Si vous avez Perl (ici je suppose qu'il n'y a pas de nouvelles lignes dans les noms de fichiers) :

0x1&

Si vous avez Python (en supposant aussi qu'il n'y a pas de nouvelles lignes dans les noms de fichiers) :

0x1&

Il y a probablement un moyen de faire la même chose en PHP, mais je ne le connais pas.

Si vous voulez travailler uniquement avec les outils POSIX, c'est un peu plus compliqué ; voir Comment lister les fichiers triés par date de modification de manière récursive (pas de commande stat disponible !) (la relecture des 10 premiers est la partie facile).

41
41
41
2011-06-16 18:11:00 +0000

Vous n'avez pas besoin de PHP ou de Python, juste de ls :

man ls:
-t sort by modification time
-r, reverse order while sorting (--reverse )
-1 list one file per line

find /wherever/your/files/hide -type f -exec ls -1rt "{}" +;

Si la commande * se termine avec un statut d'échec (c'est-à-dire Liste d'instruments trop longue ), alors vous pouvez itérer avec find. Paraphrasée de : La longueur maximale des arguments pour un nouveau processus

  • find . -print0|xargs -0 command (optimise la vitesse, si find n'implémente pas “-exec +” mais connaît “-print0”)
  • find . -print|xargs command (s'il n'y a pas d'espace blanc dans les arguments)

Si la majeure partie des arguments consiste en des chemins longs, absolus ou relatifs, alors essayez de déplacer vos actions dans le répertoire : cd /directory/with/long/path; command * Et une autre solution rapide peut consister à faire correspondre moins d'arguments : command [a-e]*; command [f-m]*; ...

10
10
10
2012-05-18 07:58:06 +0000

Vous avez seulement besoin de ls

Vous pourriez faire find /wherever/your/files/hide -type f -exec ls -1rt "{}" +; comme indiqué ci-dessus,

ou

ls -1rt `find /wherever/your/file/hides -type f`
```.
8
8
8
2014-04-24 08:12:01 +0000

Extension de la réponse de user195696 :

find . -type f -printf "%T@\t%Tc %6k KiB %p\n" | sort -n | cut -f 2-

Pour chaque fichier, cela produit d'abord l'horodatage numérique (pour le tri par, suivi de la tabulation \t), puis un horodatage lisible par l'homme, puis la taille du fichier (malheureusement les find ne peuvent pas faire en mebibytes, seulement en kibibytes), puis le nom du fichier avec le chemin relatif.

Puis -printf le trie par le premier champ numérique.

Puis sort -n se débarrasse de ce premier champ numérique qui n'est pas intéressant pour l'utilisateur. Le séparateur de champ par défaut est cut ou tabulation.

Exemple de sortie :

Thu 06 Feb 2014 04:49:14 PM EST 64 KiB ./057_h2_f7_10/h2_f7_10.class
Fri 07 Feb 2014 02:08:30 AM EST 7962976 KiB ./056_h2_f7_400/h2__rh_4e-4.mph
Fri 07 Feb 2014 02:23:24 AM EST 7962976 KiB ./056_h2_f7_400/h2_f7_400_out_Model.mph
Fri 07 Feb 2014 02:23:24 AM EST 0 KiB ./056_h2_f7_400/h2_f7_400_out.mph.status
Fri 07 Feb 2014 02:23:24 AM EST 64 KiB ./056_h2_f7_400/1579678.out
Fri 07 Feb 2014 03:47:31 AM EST 8132224 KiB ./057_h2_f7_10/h2__rh_1e-5.mph
Fri 07 Feb 2014 04:00:49 AM EST 8132224 KiB ./057_h2_f7_10/h2_f7_10_out_Model.mph
Fri 07 Feb 2014 04:00:49 AM EST 0 KiB ./057_h2_f7_10/h2_f7_10_out.mph.status
Fri 07 Feb 2014 04:00:49 AM EST 64 KiB ./057_h2_f7_10/1579679.out
Fri 07 Feb 2014 09:47:18 AM EST 9280 KiB ./056_h2_f7_400/h2__rh_4e-4.mat
Fri 07 Feb 2014 10:51:23 AM EST 9728 KiB ./018_bidomain/h2_plain__rh_1e-5.mat
Fri 07 Feb 2014 10:58:33 AM EST 9568 KiB ./057_h2_f7_10/h2__rh_1e-5.mat
Fri 07 Feb 2014 05:05:38 PM EST 64 KiB ./058_h2_f7_stationary/h2_f7_stationary.java
Fri 07 Feb 2014 06:06:29 PM EST 32 KiB ./058_h2_f7_stationary/slurm.slurm
Sat 08 Feb 2014 03:42:07 AM EST 0 KiB ./058_h2_f7_stationary/1581061.err
Sat 08 Feb 2014 03:42:14 AM EST 64 KiB ./058_h2_f7_stationary/h2_f7_stationary.class
Sat 08 Feb 2014 03:58:28 AM EST 70016 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mph
Sat 08 Feb 2014 04:12:40 AM EST 70304 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mph
Sat 08 Feb 2014 04:12:53 AM EST 70304 KiB ./058_h2_f7_stationary/h2_f7_stationary_out_Model.mph
Sat 08 Feb 2014 04:12:53 AM EST 0 KiB ./058_h2_f7_stationary/h2_f7_stationary_out.mph.status
Sat 08 Feb 2014 04:12:53 AM EST 32 KiB ./058_h2_f7_stationary/1581061.out
Mon 10 Feb 2014 11:40:54 AM EST 224 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mat
Mon 10 Feb 2014 11:42:32 AM EST 224 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mat
Mon 10 Feb 2014 11:50:08 AM EST 32 KiB ./plot_grid.m

J'ai délibérément fait en sorte que le champ “taille du fichier” comporte 6 caractères, car si on l'allonge, il devient difficile de distinguer visuellement la taille des fichiers. De cette façon, les fichiers de plus de 1e6 ko font saillie : 1 caractère signifie 1-9 Go, 2 caractères signifie 10-99 Go, etc.


Edit : voici une autre version (puisque \t plante sur MinGW/MSYS) :

find . -type f -printf "%T@\t%p\n" | sort -n | cut -f 2- | xargs -I{} ls -Glath --si {}

donnant une sortie comme :

-rw-r--r-- 1 es 23K Jul 10 2010 ./laptop_0000071.jpg
-rw-r--r-- 1 es 43M Jul 29 19:19 ./work.xcf
-rw-r--r-- 1 es 87K Jul 29 20:11 ./patent_lamps/US Patent 274427 Maxim Lamp Holder.jpg
-rw-r--r-- 1 es 151K Jul 29 20:12 ./patent_lamps/Edison screw-in socket.png
-rw-r--r-- 1 es 50K Jul 29 20:13 ./patent_lamps/1157 Lamp.jpg
-rw-r--r-- 1 es 38K Jul 29 20:14 ./patent_lamps/US06919684-20050719-D00001.png

Où :

  • find . -printf "%Tc" fait que l'occurrence de -I{} est remplacée par un argument, et les nouvelles lignes sont maintenant les séparateurs d'arguments (notez les espaces dans les noms de fichiers ci-dessus).

  • {} supprime l'impression du nom du groupe (perte d'espace).

  • ls -G produit des tailles de fichier lisibles par l'utilisateur (plus correct avec ls -h --si).

  • --si trie par temps, ce qui n'est pas pertinent ici, mais c'est ce que j'utilise généralement.

4
4
4
2016-02-24 15:18:34 +0000

Variante OS X de la réponse de @user195696 :

  1. avec horodatage :

  2. Sans horodatage :

2
2
2
2019-03-12 19:32:27 +0000

J'ai une solution simple qui fonctionne à la fois pour FreeBSD (OS X) et Linux :

find . -type f -exec ls -t {} +
```.
2
2
2
2012-07-26 07:42:44 +0000

J'ai trouvé que cela fonctionne sur Mac OS X (et suffisamment générique pour fonctionner également sur d'autres Unixen) :

find . -type f -ls | awk '{print $(NF-3), $(NF-2), $(NF-1), $NF}' | sort
```.
1
1
1
2013-12-08 09:14:14 +0000

Utilisation :

find . -type f -mtime 0 -printf "[%TD %TI:%TM%Tp] %s %p\n" | sort -n | awk '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';

Cette commande permet de trier les fichiers par date de modification.

Et s'affichera comme :

[12/05/13 03:10PM] 1.75 MB ./file.text
[12/06/13 11:52PM] 2.90 MB ./file2.mp4
[12/07/13 04:11PM] 4.88 MB ./file3.mp4
[12/07/13 09:17PM] 4.74 MB ./test.apk
1
1
1
2014-05-02 11:16:59 +0000

Si votre sélection find est très simple, vous pourrez peut-être vous en passer, et utiliser simplement ls :

ls -1 *.cc # -r -t optional
0
0
0
2014-07-04 14:58:50 +0000

J'ai amélioré la réponse Akashs en faisant en sorte que le script gère correctement les espaces dans les noms de fichiers :

find . -type f -mtime 0 -printf ";[%TD %TI:%TM%Tp];%s;%p\n" | sort -n | awk -F ";" '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';
0
0
0
2019-09-11 08:23:43 +0000

Il existe une méthode propre et robuste de sort | head par date :

Utiliser ls -l pour une jolie impression

find . ! -type d -printf "%T@ %p```
findByDate() {
    local humansize=''
    ["$1" = "-h"] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p```
Usage: findByDate [-h] [lines] [find options]
```" |
        sort -zrn |
        head -zn ${1:--0} |
        sed -z 's/^[0-9.] //' |
        xargs -0 ls -dlt${humansize}
}
```" |
    sort -zrn |
    head -zn 10 |
    sed -z 's/^[0-9.] //' |
    xargs -0 ls -lt

Comme une fonction bash :

findByDate

Cela peut être exécuté avec un ou deux arguments, ou même sans :

findByDate -h 12

Exemple :

findByDate 42 '-type l'

Listera tous les non répertoires triés par date. Nota :

Même sur une grande arborescence de système de fichiers, comme xargs reçoit une liste déjà triée, l'ordre des fichiers reste correct, même si ls doit être exécuté plusieurs fois.

findByDate -0 '( -type l -o -type b -o -type s -o -type c )'

Listera 12 autres liens symboliques récents non répertoires triés par date, avec la taille imprimée sous forme humaine lisible

findByDate() {
    local humansize=''
    ["$1" = "-h"] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p```
Usage: findByDate [-h] [lines] [find options]
```" |
        sort -zn |
        tail -zn ${1:-+0} |
        sed -z 's/^[0-9.] //' |
        xargs -0 ls -dltr${humansize}
}

Listera 42 autres liens symboliques récents

0x1&

Listera tous les liens symboliques, les périphériques de blocs, les périphériques de sockets et de caractères, triés par date.

Inversion de l'ordre

Remplacement de head par tail et changement du commutateur de sort et ls :

0x1&

Même fonction, même usage :

0x1&

0
0
0
2011-06-07 18:33:10 +0000

Je ne pense pas que find ait la possibilité de modifier l'ordre des sorties. -mtime et -mmin vous permettent de limiter les résultats aux fichiers qui ont été modifiés dans une certaine fenêtre de temps, mais la sortie ne sera pas triée – vous devrez le faire vous-même. GNU find a une option -printf qui, entre autres choses, vous permettra d'imprimer l'heure de modification de chaque fichier trouvé (chaînes de format %t ou %Tk) ; cela pourrait vous aider à trier la sortie find comme vous le souhaitez.

0
0
0
2018-06-24 23:33:20 +0000

Vous pouvez utiliser stat sur BSD et Linux (pas sur POSIX) de cette manière :

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | cut -f2-

Si vous voulez limiter le nombre :

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | head -[the number] | cut -f2-
0
0
0
2014-05-17 10:55:57 +0000

Si vous voulez commander tous les fichiers PNG par heure en $PWD :

Ce simple one-liner donne toute la flexibilité de la regexp sur find et sur ls.

find $PWD -name "*.png" -print0 | xargs -0 ls -laht | less
-1
-1
-1
2017-03-28 01:13:40 +0000

Si vous voulez juste obtenir un chemin complet de chaque élément, vous pouvez l'écrire comme ceci.

find FIND_ROOT -maxdepth 1 -type f -printf "%T@ %p\n" | sort -nr | head -10 | cut -d ' ' -f 2

-printf “%T@ %p\n ” pour donner les critères de tri (date), ‘sort -nr’ pour le tri par date, head -10 pour la liste des 10 premiers résultats, cut -d ‘ ’ -f 2 pour couper l'horodatage de tête sur chaque ligne.

-3
-3
-3
2017-03-25 09:09:59 +0000

J'ai une solution simple.

Après cd dans un répertoire, utilisez

find . -iname "*" -ls