bash - directorios - ¿Cómo encontrar recursivamente el último archivo modificado en un directorio?
contar archivos recursivamente linux (19)
Ignorando archivos ocultos - con sello de tiempo agradable y rápido
Maneja bien los espacios en los nombres de archivo, ¡no es que debas usarlos!
$ find . -type f -not -path ''*//.*'' -printf ''%TY.%Tm.%Td %THh%TM %Ta %p/n'' |sort -nr |head -n 10
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 find
abundancia se puede encontrar siguiendo el enlace.
Parece que ls
no ordena los archivos correctamente al hacer una llamada recursiva:
ls -altR . | head -n 3
¿Cómo puedo encontrar el archivo modificado más recientemente en un directorio (incluidos los subdirectorios)?
El siguiente comando funcionó en Solaris:
find . -name "*zip" -type f | xargs ls -ltr | tail -1
En Ubuntu 13, lo siguiente lo hace, tal vez un poco más rápido, ya que invierte el ordenamiento 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'' | sort -n -r | cabeza -11 | corte -f2- -d "" | sed -e ''s, ^. / ,,'' | xargs ls -U -l
Esto da una lista completa de ls sin reorganizar y omite el molesto ''./'' que ''buscar'' pone en cada nombre de archivo.
O, como una función de 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 hecho por la solución original de plundra. Gracias plundra
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 de 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 el número de archivos es lo suficientemente grande.
He usado el carácter NUL (es decir, ''/ 0'') porque, en teoría, un nombre de archivo puede contener cualquier carácter (incluido el espacio y la nueva línea), excepto ese.
Si no tiene dichos 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 funciona también en mawk.
Encontré útil el comando anterior, pero para mi caso necesitaba ver la fecha y la hora del archivo y 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
Encuentro lo siguiente más corto y con más salida interpretable:
find . -type f -printf ''%TF %TT %p/n'' | sort | tail -1
Dada la longitud fija de los tiempos de datos estandarizados del formato ISO, la clasificación lexicográfica está bien y no necesitamos la opción -n
en la clasificación.
Si desea eliminar las marcas de tiempo de nuevo, puede utilizar:
find . -type f -printf ''%TFT%TT %p/n'' | sort | tail -1 | cut -f2- -d'' ''
Escribí un paquete pypi / github para esta pregunta porque también necesitaba una solución.
https://github.com/bucknerns/logtail
Instalar:
pip install logtail
Uso: colas archivos cambiados
logtail <log dir> [<glob match: default=*.log>]
Usage2: Abre el último archivo modificado en el editor
editlatest <log dir> [<glob match: default=*.log>]
Este simple cli también funcionará:
ls -1t | head -1
Puede cambiar el -1 al número de archivos que desea enumerar.
Esto cambia de forma recursiva la hora 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
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 ordenación. Si solo desea nombres de archivos, inserte "awk ''{print $ 11}'' |" antes de ''| cabeza''
Esto parece funcionar bien, incluso con subdirectorios:
find . -type f | xargs ls -ltr | tail -n 1
En caso de que haya demasiados archivos, refine el hallazgo.
Me enfrenté al mismo problema. Necesito encontrar el archivo más reciente de forma recursiva. Encontrar tardó alrededor de 50 minutos en 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.
Muestra el último archivo con marca de tiempo legible por 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, reemplace -n1
con un número mayor
Si ejecutar stat
en cada archivo individualmente es lento, puede usar xargs
para acelerar un poco las cosas:
find . -type f -print0 | xargs -0 stat -f "%m %N" | sort -n | tail -1 | cut -f2- -d" "
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" "
Tuve la molestia de encontrar el último archivo modificado en Solaris 10. Allí no tiene la opción printf
y stat
no está disponible. Descubrí la siguiente solución que me funciona bien:
find . -type f | sed ''s/.*/"&"/'' | xargs ls -E | awk ''{ print $6," ",$7 }'' | sort | tail -1
Para mostrar el nombre de archivo, así como el uso
find . -type f | sed ''s/.*/"&"/'' | xargs ls -E | awk ''{ print $6," ",$7," ",$9 }'' | sort | tail -1
Explicación
-
find . -type f
find . -type f
encuentra y lista todos los archivos -
sed ''s/.*/"&"/''
envuelve el nombre de ruta entre comillas para manejar espacios en blanco -
xargs ls -E
envía la ruta citada als
, la opción-E
se asegura de que se devuelva una marca de tiempo completa (formato año-mes-día hora-minuto-segundos-nanosegundos ) -
awk ''{ print $6," ",$7 }''
extrae solo la fecha y la 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
Uso algo similar todo el tiempo, así como la lista top-k de los archivos modificados más recientemente. Para grandes árboles de directorios, puede ser mucho más rápido evitar la clasificación . En el caso de solo el archivo top-1 más recientemente modificado:
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, recibo el más reciente en 3.4s, una aceleración de 7.5x contra la solución de 25.5s usando ordenación.
Yo prefiero este, es más corto:
find . -type f -print0|xargs -0 ls -drt|tail -n 1
find . -type f -printf ''%T@ %p/n'' | sort -n | tail -1 | cut -f2- -d" "
Para un árbol enorme, puede ser difícil mantener todo en la memoria.
%T@
te da el tiempo de modificación como una marca de tiempo de Unix, sort -n
ordena numéricamente, tail -1
toma la última línea (la marca de tiempo más alta), cut -f2 -d" "
corta el primer campo (la marca de tiempo) de la salida .
Edición: así como -printf
es probablemente solo GNU, el uso de aj-real de stat -c
también lo es. Aunque es posible hacer lo mismo en BSD, las opciones para formatear son diferentes (parecería -f "%m %N"
)
Y me perdí la parte de plural; Si desea más que el último archivo, simplemente suba el argumento de la cola.