Cómo enumerar archivos ordenados por fecha de modificación de forma recursiva (¡no hay un comando stat disponible!


31

¿Cómo puedo obtener la lista de todos los archivos en el directorio actual junto con su fecha de modificación y ordenados por esa fecha?

Ahora sé cómo lograr eso con find, staty sort, pero por alguna extraña razón, statno está instalado en la caja y es poco probable que pueda instalarlo.

¿Alguna otra opción?

PD: gcctampoco está instalado


¿Puedes subir un binario compilado y ejecutarlo allí?
imz - Ivan Zakharyaschev

@imz: sí, ese es otro camino a seguir. Sin find -printfembargo, la acción parece ser la más fácil.
alex

Respuestas:


27

Mi método más corto usa zsh:

print -rl -- **/*(.Om)

(agregue los Dcalificadores glob si también desea enumerar los archivos ocultos o los archivos en directorios ocultos).

Si tiene GNU find, haga que imprima los tiempos de modificación del archivo y ordene por eso. Supongo que no hay nuevas líneas en los nombres de archivo.

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

Si tiene Perl (nuevamente, suponiendo que no haya nuevas líneas en los nombres de archivo):

find . -type f -print |
perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="\n";
        print sort {$_{$b} <=> $_{$a}} keys %_;  # print by decreasing age
    }'

Si tiene Python (nuevamente, suponiendo que no haya nuevas líneas en los nombres de archivo):

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]): print f'

Si tiene acceso SSH a ese servidor, monte el directorio sobre sshfs en una máquina mejor equipada:

mkdir mnt
sshfs server:/path/to/directory mnt
zsh -c 'cd mnt && print -rl **/*(.Om)'
fusermount -u mnt

Con solo las herramientas POSIX, es mucho más complicado, porque no hay una buena manera de encontrar el tiempo de modificación de un archivo. La única forma estándar de recuperar los tiempos de un archivo es ls, y el formato de salida depende del entorno local y es difícil de analizar.

Si puede escribir en los archivos, y solo le importan los archivos normales, y no hay nuevas líneas en los nombres de los archivos, aquí hay un error horrible: cree enlaces duros a todos los archivos en un solo directorio y ordénelos por hora de modificación.

set -ef                       # disable globbing
IFS='
'                             # split $(foo) only at newlines
set -- $(find . -type f)      # set positional arguments to the file names
mkdir links.tmp
cd links.tmp
i=0 list=
for f; do                     # hard link the files to links.tmp/0, links.tmp/1, …
  ln "../$f" $i
  i=$(($i+1))
done
set +f
for f in $(ls -t [0-9]*); do  # for each file, in reverse mtime order:
  eval 'list="${'$i'}         # prepend the file name to $list
$list"'
done
printf %s "$list"             # print the output
rm -f [0-9]*                  # clean up
cd ..
rmdir links.tmp

La forma más fácil es probablemente find . -print | xargs -n99999 -s999999 ls -ltr. Pero eso tiene el problema de que (1) xargspuede no permitir -mmás de 512 o -smás de 5120, y (b) incluso si puede evitar eso, todavía hay un tamaño máximo impuesto por el núcleo de la lista de argumentos combinados y el entorno. La mayoría de sus ideas (excepto las de Perl y Python) tienen el mismo problema, por lo que evité específicamente construir líneas de comando largas.
geekosaur

En particular, regularmente recibo errores de "lista de argumentos demasiado larga" usando zshglobos recursivos en el caso general.
geekosaur

@geekosaur: solo el último kludge horrible tiene un problema con largas líneas de comando. En zsh, puede hacer mucho con las funciones integradas (por ejemplo print -rl **/*, el único límite es la cantidad de memoria libre que tiene), y más allá de eso hay zargs. Su propuesta de find … | xargs … lsse ordenará correctamente si xargstermina invocando lssolo una vez, y no funcionará si hay caracteres especiales en los nombres de archivo.
Gilles 'SO- deja de ser malvado'

muchas gracias por la respuesta extremadamente detallada con muchas opciones! :)
alex

Y es por eso que amo zsh.
Profpatsch

14

Asumiendo GNU find:

find . -printf '%T@ %c %p\n' | sort -k 1n,1 -k 7 | cut -d' ' -f2-

Cambie 1n,1a 1nr,1si desea que los archivos enumerados sean los más recientes primero.

Si no tiene GNU, findse vuelve más difícil porque lsel formato de marca de tiempo varía mucho (los archivos modificados recientemente tienen un estilo diferente de marca de tiempo, por ejemplo).


En realidad, también puede cambiar el formato de fecha y hora con ls --time-style="...": no estoy seguro de si esto es estándar o GNU ls, probablemente GNU.
asoundmove

Definitivamente GNU.
geekosaur

@asoundmove: desafortunadamente, el cuadro es demasiado viejo (RedHat 7.2) y lsno tiene esa opción.
alex

7

En una Mac no hay ningún argumento -printf para encontrar, pero puede hacerlo en su lugar:

find . -print0 | xargs -0 -n 100 stat -f"%m %Sm %N" | sort -n|awk '{$1="";print}'



0

Ignorar 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

Sefind puede encontrar más en abundancia siguiendo el enlace.


0

Hablando en general de encontrar archivos por fecha (esto no funcionará para el póster original, pero terminé aquí, así que pensé que otros también podrían hacerlo). En mi caso de uso, quiero enumerar los archivos con el fin de revisarlos antes de eliminarlos.

Con findutils 4.6.0 me gusta:

find . -type f -mtime +270 -exec ls -laFGht --time-style=iso {} \+

El comando anterior busca archivos ( -type f), en el directorio de trabajo actual ( .) que se modificaron hace más de 270 días ( -mtime +270también -mtime 0producirá las últimas 24 horas y -mtime -5muestra los últimos 5 días). Luego se usa lspara enumerarlos por fecha, el más nuevo primero ( -exec ls -laFGht --time-style=iso {} \+)

Aquí hay una muestra de la salida:

-rwxrwx---+ 1 user1 208M 2018-07-16  ./filename.bak*
-rwxrwx---+ 1 user1  702 2018-07-15  ./filename.ldf*
-rwxrwx---+ 1 user1 208M 2018-07-15  ./filename.bak*

Lo mejor de esto es que una vez que la lista ha sido revisada, es simple reemplazar la parte de la lista con el findcomando eliminar:

find . -type f -mtime +270 -delete
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.