Usuario del software
2011-06-07 18:23:57 +0000 2011-06-07 18:23:57 +0000
152

Unix/Linux encontrar y ordenar por fecha de modificación

¿Cómo puedo hacer un simple find que ordene los resultados por la modificación más reciente?

Aquí está el actual find que estoy usando (estoy haciendo un escape de shell en PHP, así que ese es el razonamiento de las variables):

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

¿Cómo puedo hacer que esto ordene la búsqueda por lo más recientemente modificado? (Tenga en cuenta que no quiero que ordene 'después' de la búsqueda, sino que encuentre los resultados en base a lo que fue modificado más recientemente).

Respuestas [17]

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

Utiliza esto:

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

printf argumentos de man find :

  • %Tk: Hora de la última modificación del archivo en el formato especificado por k.

  • @: segundos desde el 1 de enero de 1970, 00:00 GMT, con parte fraccionaria.

  • c: fecha y hora de la localidad (Sat Nov 04 12:02:33 EST 1989).

  • %p: Nombre del archivo.

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

El método más fácil es usar zsh, gracias a sus calificadores glob .

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

Si tiene GNU find, haga que imprima las horas de modificación del archivo y ordene por eso.

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 tiene GNU find pero no otras utilidades GNU, use nuevas líneas como separadores en lugar de nulos; perderá el soporte para nombres de archivo que contengan nuevas líneas.

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 tiene Perl (aquí asumiré que no hay nuevas líneas en los nombres de archivo):

0x1&

Si tiene Python (también asumiendo que no hay nuevas líneas en los nombres de archivo):

0x1&

Probablemente hay una manera de hacer lo mismo en PHP, pero no la conozco.

Si quiere trabajar sólo con herramientas POSIX, es bastante más complicado; vea Cómo listar archivos ordenados por fecha de modificación recursivamente (¡no hay comando stat disponible!) (retatar los primeros 10 es la parte fácil).

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

No necesita PHP o Python, sólo 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 el comando * sale con un estado de fallo (es decir Lista de argumentos demasiado larga ), entonces puede iterar con find. Parafraseado de: La longitud máxima de los argumentos para un nuevo proceso

  • find . -print0|xargs -0 command (optimiza la velocidad, si find no implementa "-exec +" pero conoce "-print0")
  • find . -print|xargs command (si no hay espacios en blanco en los argumentos)

Si la mayor parte de los argumentos consiste en rutas largas, absolutas o relativas, entonces trate de mover sus acciones dentro del directorio: cd /directory/with/long/path; command * Y otra solución rápida puede ser hacer coincidir menos argumentos: command [a-e]*; command [f-m]*; ...

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

Sólo necesitas ls

Podrías hacer find /wherever/your/files/hide -type f -exec ls -1rt "{}" +; como se indica arriba,

o

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

Ampliando la respuesta de user195696 :

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

Para cada archivo, esto produce primero la marca de tiempo numérica (para ordenar por, seguido por la tabulación \t), luego una marca de tiempo legible por humanos, luego el tamaño del archivo (desafortunadamente find no puede hacerlo en mebibytes, solo en kibibytes), luego el nombre del archivo con la ruta relativa.

Luego -printf lo ordena por el primer campo numérico.

Luego sort -n se deshace de ese primer campo numérico que no interesa al usuario. (Imprime el segundo campo en adelante.) El separador de campos por defecto es cut o tabulación.

Ejemplo de salida:

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

Deliberadamente hice el campo filesize de 6 caracteres, porque si se hace más largo, se hace difícil distinguir visualmente lo grande que son los archivos. De esta manera, los archivos mayores de 1e6 KiB sobresalen: por 1 carácter significa 1-9 GB, por 2 caracteres significa 10-99 GB, etc.

  • *

Editar: aquí hay otra versión (ya que \t falla en MinGW/MSYS):

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

Dando una salida como:

-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

Donde:

  • find . -printf "%Tc" hace que la ocurrencia de -I{} sea reemplazada por un argumento, y las nuevas líneas son ahora los separadores de los argumentos (nótese los espacios en los nombres de los archivos arriba).

  • {} suprime la impresión del nombre del grupo (desperdicio de espacio).

  • ls -G produce tamaños de archivo legibles para los humanos (más correcto con ls -h --si).

  • --si ordena por tiempo, lo cual es irrelevante aquí, pero es lo que suelo usar.

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

Variante para OS X de la respuesta de @user195696:

  1. Con marca de tiempo:

  2. Sin marca de tiempo:

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

Tengo una solución sencilla que funciona tanto para FreeBSD (OS X) como para Linux:

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

He descubierto que esto hace el trabajo en Mac OS X (y lo suficientemente genérico como para funcionar en otros Unixen también):

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

Utilice:

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

Este comando ordenará los archivos por fecha de modificación.

Y se mostrará como:

[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
2014-05-02 11:16:59 +0000

Si su selección de find es muy simple, podría prescindir de ella y utilizar simplemente ls:

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

He mejorado la respuesta de Akashs haciendo que el script maneje correctamente los espacios en blanco en los nombres de los archivos:

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
2019-09-11 08:23:43 +0000

Hay una forma limpia y robusta de sort | head por fecha:

Usando ls -l para la impresión bonita

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

Como una función bash :

findByDate

Puede ejecutarse con uno o dos argumentos, o incluso sin ellos:

findByDate -h 12

Ejemplo:

findByDate 42 '-type l'

Listará todos los no directorios ordenados por fecha. Nota:

Incluso en un árbol de sistema de archivos grande, como xargs recibe una lista ya ordenada, el orden de los archivos permanece correcto, incluso si ls debe ser ejecutado muchas veces.

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

Listará 12 más recientes no directorios ordenados por fecha, con el tamaño impreso en forma llegable

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}
}

Listará 42 más recientes enlaces simbólicos

0x1&

Listará todos los enlaces simbólicos, dispositivos de bloque, sockets y dispositivos de caracteres, ordenados por fecha.

Invertir el orden

Reemplazar head por tail y cambiar el interruptor de sort y ls:

0x1&

Misma función, mismo uso:

0x1&

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

No creo que find tenga ninguna opción para modificar el orden de salida. -mtime y -mmin le permitirán restringir los resultados a los archivos que hayan sido modificados dentro de una ventana de tiempo determinada, pero la salida no estará ordenada -- tendrá que hacerlo usted mismo. GNU find tiene una opción -printf que, entre otras cosas, le permitirá imprimir la hora de modificación de cada archivo encontrado (cadenas de formato %t o %Tk) ; eso podría ayudarle a ordenar la salida de find de la forma que desee.

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

Puede utilizar stat en BSD y Linux (no en POSIX) de esta manera:

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

Si quiere limitar el número:

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

Si quiere ordenar todos los archivos PNG por tiempo en $PWD:

Esta simple línea le da toda la flexibilidad de la regexp en find y en ls.

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

Si sólo quieres obtener una ruta completa de cada elemento puedes escribirlo así

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

Donde -printf "%T@ %p\n " para dar el criterio de ordenación (fecha), 'sort -nr' para ordenar por fecha, head -10 para listar los 10 primeros resultados, cut -d ' ' -f 2 para cortar el timestamp inicial de cada línea.

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

Tengo una solución sencilla.

Después de cd a un directorio, utilice

find . -iname "*" -ls

-3