web-dev-qa-db-fra.com

Unix/Linux rechercher et trier par date modifiée

Comment puis-je faire une simple find qui ordonnerait les résultats les plus récemment modifiés?

Voici la find actuelle que j'utilise (je fais un échappement Shell en PHP, donc c'est le raisonnement pour les 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.)

119
Richard Easton

Utilisez ceci:

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

printf arguments from man find :

  • %Tk: heure de dernière modification du fichier au format spécifié par k.

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

  • c: date et heure de la localisation (sam 4 nov. 12:02:33 EST 1989).

  • %p: nom du fichier.

127
user195696

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-le imprimer les temps de modification du fichier et triez-le.

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 la prise en charge des 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 (aucune commande stat disponible!) (retatiner les 10 premiers est la partie facile).

82
Gilles

Vous n'avez pas besoin de PHP ou de Python, seulement 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 (par exemple, La liste d'arguments est trop longue ), vous pouvez effectuer une itération avec find. Paraphrased from: 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 à faire correspondre moins d'arguments: command [a-e]*; command [f-m]*; ...

Vous avez seulement besoin 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`
9
skippy1910

Extension de réponse de user195696 :

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

Pour chaque fichier, cela commence par afficher l’horodatage numérique (pour trier par, suivi de la tabulation \t), puis un horodatage lisible par l’homme, puis la taille du fichier (malheureusement, le -printf du find ne peut pas être exprimé en mégaoctets, uniquement le kibibytes), puis le nom de fichier avec chemin relatif.

Ensuite, sort -n le trie en fonction du premier champ numérique.

Ensuite, cut supprime 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 \t 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 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 que find . -printf "%Tc" se bloque sur 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{} fait que l'occurrence de {} soit remplacée par un argument, et / newlines 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 --si produit des tailles de fichier lisibles par l'homme (plus correct avec --si).

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

6
Evgeni Sergeev

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) }'
    
3
user9399

Essayer:

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

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

1
Good.Dima

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

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

J'ai constaté que cela se faisait 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
1
Bryan Petty

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
1
Akash

Je ne pense pas que find dispose d’options pour modifier l’ordre de sortie. -mtime et -mmin vous permettront de limiter les résultats aux fichiers modifiés au cours d'une certaine période, mais le résultat ne sera pas trié - 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îne de format %t ou %Tk); cela peut vous aider à trier la sortie find comme vous le souhaitez.

0
Jim Lewis

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 }
    }}';
0
jan

Vous pouvez utiliser stat sous BSD et Linux (pas sous 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
drewk

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

Ce simple one-liner donne toute la flexibilité de l'expression rationnelle sur find et sur ls.

find $PWD -name "*.png" -print0 | xargs -0 ls -laht | less
0
john smith