Unix / Linux rechercher et trier par date modifiée

138

Comment puis-je faire un simple findqui ordonnera les résultats par le plus récemment modifié?

Voici le courant que findj'utilise (je fais un shell shell en PHP, c'est donc le raisonnement des variables):

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

Comment pourrais-je avoir cette commande la dernière recherche modifiée? (Remarque: je ne souhaite pas qu'il trie "après" la recherche, mais trouve les résultats en fonction de ce qui a été modifié le plus récemment.)

Peter Mortensen
la source
github.com/shadkam/recentmost ferait ce qui est souhaité - mais il faut le construire
user3392225 Le

Réponses:

153

Utilisez ceci:

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

printfarguments 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, 00h00 GMT, avec partie fractionnaire.

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

  • %p: Nom du fichier.

utilisateur195696
la source
5
+1 Très utile, c'est la première réponse que j'ai trouvée avec une sortie de date lisible / utile
Jake N
plus fiable (et très simple) que le temps est donné pour être numérique séquentiel (donc toujours correctement triable), thx!
Aquarius Power
1
J'ai cet alias pour trouver les fichiers récents dans mon ~/.zshrc: fr () { find ./ -iname "*"$@"*" -printf "%T@ %Td-%Tb-%TY %Tk:%TM %p\n" | sort -n | cut -d " " -f 2- | grep -i "$@" ; }Il trouve tous les fichiers contenant le motif du premier argument passé à la commande ( fr <pattern>) de manière récursive et les trie avec le dernier.
joelostblom
C'est bien !!! Pour utiliser avec des liens symboliques, utilisezfind -L ...
Varun Chandak
1
Vous voudrez peut-être utiliser ssedpour vous débarrasser de la fraction de secondes et toujours utiliser ISO8601 comme l'a montré @PeterMortensen:find . -type f -printf "%TY-%Tm-%TdT%TT %p\n" | sort -r | ssed -R 's/^([^.]+)\.\d+ (.*)$/\1 \2/'
Ludovic Kuty le
83

La méthode la plus simple consiste à utiliser zsh, grâce à ses qualificatifs glob .

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

Si vous avez GNU find, faites-lui imprimer les temps de modification du fichier et triez-le en conséquence.

find -type f -printf '%T@ %p\0' |
sort -zk 1nr |
sed -z 's/^[^ ]* //' | tr '\0' '\n' | head -n 10

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

find -type f -printf '%T@ %p\n' |
sort -k 1nr |
sed 's/^[^ ]* //' | head -n 10

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

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];
    }'

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

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'

Il existe probablement un moyen de faire la même chose en PHP, mais je ne le sais 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!) (retatiner les 10 premiers est la partie facile).

Gilles
la source
Je pense que la findversion montre les fichiers les plus anciens, et que vous devez ajouter l' -roption à sort.
Quentin Pradet
Mon sed dit qu'il n'a pas l'option -z.
Kef Schecter
@KefSchecter Ensuite, utilisez les nouvelles lignes comme séparateurs, mais vous perdrez la prise en charge des nouvelles lignes dans les noms de fichiers.
Gilles
Ce qui précède est pour python2. Si vous avez seulement python3, quelques petites modifications: python3 -c 'import os, sys; times = {} pour f dans sys.stdin.readlines (): f = f [0: -1]; times [f] = os.stat (f) .st_mtime pour f in (trié (times.keys (), clé = lambda f: fois [f], reverse = True)) [: 10]: print (f); '
Neil McGill
40

Vous n'avez pas besoin de PHP ou Python, juste 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 une liste d'arguments trop longue ), vous pouvez effectuer une itération avec find. Paraphrasé dans: 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, essayez de déplacer vos actions dans le répertoire: cd /directory/with/long/path; command *une autre solution rapide consiste peut-être à faire correspondre moins d'arguments:command [a-e]*; command [f-m]*; ...

Рослав Рахматуллин
la source
1
S'il y a beaucoup de fichiers, cela échoue avec 'Argument list too long' sur la ls.
occulus le
1
C'est vrai, mais je crois que la question était "comment puis-je faire une simple découverte ..."
рослав Рахматуллин
2
ls ne cite pas les noms de fichiers d'une manière que xargs peut comprendre (pas d'option -0, et les différents styles de citation sont inadéquats)
Tobu
10

Vous n'avez besoin que de ls

Vous pouvez 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`
skippy1910
la source
2
S'il y a beaucoup de fichiers, cela échoue avec 'Argument list too long' sur la ls. Peut-être recook pour utiliser xargs?
occulus le
2
Mais si vous xargsappelez lsplusieurs fois, le tri sera interrompu.
Aaron D. Marasco
Cela échoue pour les fichiers avec des espaces dans leurs noms. Aucun conseil?
user74094
Je suis tombé par hasard sur cette réponse et c’était exactement ce dont j'avais besoin dans une situation similaire. Question: que fait-on +;à la fin? Il semble donner le même résultat sans le ;mais cela ne fonctionne pas sans le +?
RocketNuts
C'est exactement la même chose qu'une autre réponse postée 8 mois auparavant, à l'exception de la partie concernant l'utilisation de "ls -1rt` find… `", qui est cassé
Clément
7

Extension de la réponse de l'utilisateur195696 :

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

Pour chaque fichier, cette première sortie l'horodatage numérique (pour le tri par, suivi par tabulation \t), puis un horodatage lisible par l' homme, le filesize (malheureusement findde -printfne peut pas faire dans mebibytes, seulement kibibytes), puis le nom du fichier avec le parent chemin.

Puis le sort -ntrie par le premier champ numérique.

Puis cutse débarrasse de ce premier champ numérique qui n’a aucun intérêt pour l’utilisateur. (Imprime le deuxième champ en avant.) Le séparateur de champ par défaut est \tou 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 créé 6 caractères pour le champ de taille de fichier, car si on le rend plus long, il devient difficile de distinguer visuellement la taille des fichiers. Ainsi, les fichiers dont la taille est supérieure à 1e6 Ko font saillie: par 1 caractère signifie entre 1 et 9 Go, par 2 caractères, entre 10 et 99 Go, etc.


Edit: voici une autre version (depuis le find . -printf "%Tc"crash de MinGW / MSYS):

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

Donner 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ù:

  • -I{}provoque le {}remplacement de l'occurrence par un argument, et les nouvelles lignes sont maintenant les séparateurs d'arguments (notez les espaces dans les noms de fichiers ci-dessus).

  • ls -G supprime l’impression du nom du groupe (perte d’espace).

  • ls -h --siproduit des tailles de fichiers lisibles par l’homme (plus correct avec --si).

  • ls -t trie par le temps, ce qui est sans importance ici, mais c'est ce que j'utilise généralement.

Evgeni Sergeev
la source
1
Remarque: pour trier par taille de fichier , remplacez simplement T@par par sdans l’une des commandes ci-dessus.
Evgeni Sergeev
3

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

  1. Avec horodatage:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r
    
  2. Sans horodatage:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r | awk -F' ' '{ print substr($0, length($1) + 2) }'
    
utilisateur9399
la source
2

J'ai constaté que cela se fait sous 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
Bryan Petty
la source
2
Malheureusement, ceci affiche les noms de mois localisés sur ma configuration croate, rendant le tri incorrect.
Ivan Vučica
La réponse de user195696 fonctionne pour la configuration croate (et autres).
Peter Mortensen
1

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

ls -1 *.cc # -r -t optional
djc
la source
1

Essayer:

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

Mais il est également utile de filtrer les données par -mmin/ -mtimeet -type.

Peter Mortensen
la source
1

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 va trier les fichiers par date de modification.

Et afficher 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
Akash
la source
J'ai amélioré ce script pour gérer les espaces dans les noms de fichiers, voir superuser.com/a/777007/134532
janv.
1

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

find . -type f -exec ls -t {} +
Alex Shchur
la source
Cela fonctionne parfaitement - devrait être la réponse correcte, ou au moins mieux noté!
digitaltoast
0

Je ne pense pas qu’il findexiste une option pour modifier l’ordre de sortie. -mtimeet -mminvous permettra de limiter les résultats aux fichiers qui ont été modifiés dans une certaine fenêtre temporelle, mais le résultat ne sera pas trié - vous devrez le faire vous-même. GNU finda une -printfoption qui vous permettra, entre autres, d’imprimer l’heure de modification de chaque fichier trouvé (chaînes de format %tou %Tk); cela pourrait vous aider à trier la findsortie comme vous le souhaitez.

Jim Lewis
la source
0

J'ai amélioré la réponse Akash en rendant le script gérant 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 }
    }}';
Jan
la source
0

Si vous souhaitez commander tous les fichiers PNG par heure dans $PWD:

Ce simple one-liner donne toute la souplesse d’expression rationnelle, encore findet encore ls.

find $PWD -name "*.png" -print0 | xargs -0 ls -laht | less
John Smith
la source
0

Vous pouvez utiliser statsur 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-
Drewk
la source
0

Il y a un moyen propre et robuste de sort | headpar date:

Utilisation ls -lde jolis imprimés

find . ! -type d -printf "%T@ %p\0" |
    sort -zrn |
    head -zn 10 |
    sed -z 's/^[0-9.]\+ //' |
    xargs -0 ls -lt

En tant que fonction :

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

Cela pourrait être exécuté avec un ou deux arguments, voire sans:

Usage: findByDate [-h] [lines] [find options]

Échantillon:

findByDate

Répertorera tous les non répertoires triés par date Nota:

Même sur un grand système de fichiers, comme la xargs liste déjà triée est reçue, l'ordre des fichiers reste correct, même s'il lsdoit être exécuté plusieurs fois.

findByDate -h 12

Répertoriera 12 répertoires non récents plus récents triés par date, avec la taille imprimée sous une forme lisible par l'homme

findByDate 42 '-type l'

Fera la liste de 42 liens symboliques plus récents

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

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

Inverser l'ordre

Remplacement headpar tailet changer le commutateur de sortet ls:

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

Même fonction, même usage:

Usage: findByDate [-h] [lines] [find options]
F. Hauri
la source
-1

Si vous voulez juste obtenir un chemin complet pour chaque article, vous pouvez é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 trier par date,
tête -10 pour répertorier les 10 meilleurs résultats,
couper -d '' -f 2 pour couper les horodatage principal sur chaque ligne.

David Jung
la source
cut -d ' ' -f 2se cassera si les noms de fichiers contiennent des espaces.
F. Hauri
-3

J'ai une solution simple.

Après cdun répertoire, utilisez

find . -iname "*" -ls

chanter
la source
1
Cela ne trie pas par date de modification.
DavidPostill