¿Cómo encontrar recursivamente el último archivo modificado en un directorio?

Respuestas:

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

Para un árbol enorme, puede ser difícil sortmantener todo en la memoria.

%T@le da el tiempo de modificación como una marca de tiempo unix, sort -nordena numéricamente, tail -1toma la última línea (marca de tiempo más alta), cut -f2 -d" "corta el primer campo (la marca de tiempo) de la salida.

Editar: al igual que -printfprobablemente sea solo GNU, también se usa un uso real de stat -c. Aunque es posible hacer lo mismo en BSD, las opciones para formatear son diferentes ( -f "%m %N"parece)

Y me perdí la parte del plural; si quieres más que el último archivo, solo sube el argumento de cola.

plundra
fuente
77
Si el orden es importante, puede cambiar el uso en sort -rn | head -3lugar de sort -n | tail -3. Una versión proporciona los archivos del más antiguo al más nuevo, mientras que la otra va del más nuevo al más antiguo.
Don Faulkner
3
Tenía un directorio enorme (unos diez mil archivos pequeños) y estaba preocupado por el rendimiento, pero ... ¡este comando se ejecutó en menos de un segundo! Genial, muchas gracias !!! :-)
lucaferrario
2
"Para un árbol enorme, podría ser difícil para una especie mantener todo en la memoria". sortcreará archivos temporales (en /tmp) según sea necesario, por lo que no creo que sea una preocupación.
Vladimir Panteleev
1
modificándolo a: -printf '%T@ %Tb %Td %TY %p\n'le dará un sello de fecha (si es necesario) (similar a ls)
bshea
1
Encuentro lo siguiente más corto y con una salida más interpretable:find . -type f -printf '%TF %TT %p\n' | sort | tail -1
snth
129

Siguiendo con la respuesta de @ plundra , aquí está la versión BSD y OS X:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "
Emerson Farrugia
fuente
1
¿El BSD / OS X findadmite en +lugar de \;? Porque eso hace lo mismo (pasar múltiples archivos como parámetros), sin la -print0 | xargs -0tubería.
DevSolar
¿Qué hacer si quiero modificar los últimos 5 o n número de archivos en orden descendente?
khunshan
@khunshan cambia el head -1ahead -5
Emerson Farrugia
20

En lugar de ordenar los resultados y conservar solo los últimos modificados, puede usar awk para imprimir solo el que tenga el mayor tiempo de modificación (en tiempo unix):

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

Esta debería ser una forma más rápida de resolver su problema si la cantidad de archivos es lo suficientemente grande.

He usado el carácter NUL (es decir, '\ 0') porque, teóricamente, un nombre de archivo puede contener cualquier carácter (incluido el espacio y la nueva línea) pero eso.

Si no tiene esos nombres de archivo patológicos en su sistema, también puede usar el carácter de nueva línea:

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

Además, esto también funciona en mawk.

marco
fuente
Esto podría adaptarse fácilmente para mantener los tres más recientes.
Pausado hasta nuevo aviso.
1
Esto no funciona con mawkla alternativa estándar de Debian.
Jan
No, pero en ese caso puedes usar el carácter de nueva línea si no te molesta;)
marco
10

Tuve el problema de encontrar el último archivo modificado en Solaris 10. No findtiene la printfopción y statno está disponible. Descubrí la siguiente solución que funciona bien para mí:

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

Para mostrar el nombre de archivo también use

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

Explicación

  • find . -type f encuentra y enumera todos los archivos
  • sed 's/.*/"&"/' ajusta el nombre de ruta entre comillas para manejar espacios en blanco
  • xargs ls -Eenvía la ruta entre comillas ls, la -Eopción asegura que se devuelva una marca de tiempo completa (formato año-mes-día hora-minuto-segundos-nanosegundos )
  • awk '{ print $6," ",$7 }' extrae solo fecha y hora
  • awk '{ print $6," ",$7," ",$9 }' extrae fecha, hora y nombre de archivo
  • sort devuelve los archivos ordenados por fecha
  • tail -1 devuelve solo el último archivo modificado
Florian Feldhaus
fuente
9

Esto parece funcionar bien, incluso con subdirectorios:

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

En caso de demasiados archivos, refine el hallazgo.

mgratia
fuente
1
La -lopción de lsparece innecesaria. Solo -trparece suficiente.
Acumenus
66
Esto parece ordenar por directorio, por lo que no necesariamente mostrará el último archivo
Fabian Schmengler
1
En caso de que haya espacios en las rutas de archivo, mejor hacerlo:find . -type f -print0 | xargs -0 ls -ltr | tail -n 1
Mantenimiento periódico
Esto no encuentra los últimos archivos para mí.
K.-Michael Aye
1
Piense que esto se rompe si hay espacios en los nombres de archivo
waferthin
7

Muestra el último archivo con marca de tiempo legible para humanos:

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

El resultado se ve así:

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

Para mostrar más archivos, reemplácelos -n1por un número mayor

Fabian Schmengler
fuente
5

Uso algo similar todo el tiempo, así como la lista de top-k de los archivos modificados más recientemente. Para árboles de directorios grandes, puede ser mucho más rápido evitar la ordenación . En el caso de solo el archivo top-1 modificado más recientemente:

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

En un directorio que contiene 1.7 millones de archivos, obtengo el más reciente en 3.4s, una aceleración de 7.5x contra la solución de 25.5s usando sort.

Pierre D
fuente
Muy bueno: acabo de intercambiar la última impresión con: system ("ls -l $ f") if eof () para ver la fecha de una manera agradable también.
Martin T.
@MartinT. : genial, y de nada. Es extraño para mí que la gente tenga este instinto de ordenar las cosas (O (n log n)) cuando hay un método O (n) disponible. Esta parece ser la única respuesta para evitar la clasificación. Por cierto, el objetivo del comando que sugerí es solo encontrar la ruta del último archivo. Puede alias el comando en su shell (por ejemplo, como lastfile) y luego puede hacer lo que quiera con el resultado, como ls -l $(lastfile .), o open $(lastfile .)(en una Mac), etc.
Pierre D
Oh, estoy corregido: veo otra respuesta a continuación (@marco). +1.
Pierre D
4

Esto da una lista ordenada:

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

Invierta el orden colocando una '-r' en el comando de clasificación. Si solo desea nombres de archivo, inserte "awk '{print $ 11}' |" antes '| cabeza'

Karlo
fuente
3

En Ubuntu 13, lo siguiente lo hace, tal vez un poco más rápido, ya que invierte el orden y usa 'cabeza' en lugar de 'cola', lo que reduce el trabajo. Para mostrar los 11 archivos más nuevos en un árbol:

encontrar . -tipo f -printf '% T @% p \ n' | ordenar -n -r | cabeza -11 | cortar -f2- -d "" | sed -e 's, ^. / ,,' | xargs ls -U -l

Esto proporciona una lista completa de ls sin volver a ordenar y omite el molesto './' que 'find' pone en cada nombre de archivo.

O, como una función 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
}

Aún así, la mayor parte del trabajo fue realizado por la solución original de plundra. Gracias plundra

RickyS
fuente
3

Me enfrenté al mismo problema. Necesito encontrar el archivo más reciente de forma recursiva. encontrar tomó alrededor de 50 minutos para encontrar.

Aquí hay un pequeño script para hacerlo más rápido:

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

Es una función recursiva que obtiene el elemento modificado más reciente de un directorio. Si este elemento es un directorio, la función se llama de forma recursiva y busca en este directorio, etc.

AnatomicJC
fuente
3

Encuentro lo siguiente más corto y con una salida más interpretable:

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

Dada la longitud fija de las fechas y horas del formato ISO estandarizado, la clasificación lexicográfica está bien y no necesitamos la -nopción en la clasificación.

Si desea eliminar las marcas de tiempo nuevamente, puede usar:

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '
enésimo
fuente
2

Si ejecutar statcada archivo individualmente es lento, puede usarlo xargspara acelerar un poco las cosas:

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

Esto cambia recursivamente el tiempo de modificación de todos los directorios en el directorio actual al archivo más nuevo en cada directorio:

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
rwhirn
fuente
1
Se rompe mal si alguno de los directorios contiene espacios; necesita establecer IFS y usar comillas: IFS = $ '\ n'; para dir en $ (find ./ -type d); hacer eco "$ dir"; encuentre "$ dir" -tipo f -printf '% T @ "% p" \ n' | ordenar -n | cola -1 | cortar -f2- -d "" | xargs -I {} toque -r {} "$ dir"; hecho;
Andy Lee Robinson
2

Este simple cli también funcionará:

ls -1t | head -1

Puede cambiar el -1 al número de archivos que desea enumerar

Ankit Zalani
fuente
10
No, no lo hará, ya que no es recursivo.
arataj
1

Encontré el comando anterior útil, pero para mi caso también necesitaba ver la fecha y la hora del archivo, tuve un problema con varios archivos que tienen espacios en los nombres. Aquí está mi solución de trabajo.

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

El siguiente comando funcionó en Solaris:

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

Ignorar archivos ocultos - con un sello de tiempo agradable y rápido

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

Resultado

Maneja bien los espacios en los nombres de archivo, ¡no es que se deban usar!

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

Más

Más find abundancia siguiendo el enlace.

Serge Stroobandt
fuente
1

Para buscar archivos en / target_directory y todos sus subdirectorios, que se han modificado en los últimos 60 minutos:

$ find /target_directory -type f -mmin -60

Para buscar los archivos modificados más recientemente, ordenados en el orden inverso del tiempo de actualización (es decir, los archivos actualizados más recientemente primero):

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

Prefiero este, es más corto:

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

Escribí un paquete pypi / github para esta pregunta porque también necesitaba una solución.

https://github.com/bucknerns/logtail

Instalar en pc:

pip install logtail

Uso: colas cambiaron archivos

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

Uso2: abre el último archivo modificado en el editor

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