¿Cómo administrar una gran cantidad de archivos en shell?

9

$ ls ./dir_with_huge_amount_of_files/errors/

Supongamos que un directorio está lleno de imágenes con marcas de tiempo Unix, quiero decir, mucho medido en muchos GB o incluso más. Los comandos de shell como lsrecibirán advertencias de estilo de desbordamiento porque no están diseñados para funcionar con millones (o más) de imágenes. ¿Cómo puedo administrar una cantidad tan grande de archivos? Si, por ejemplo, quiero encontrar la imagen en el medio (de acuerdo con la marca de tiempo en el nombre y la hora de creación), ¿hay algún sistema de archivos que ofrezca una función de búsqueda integrada? ¿Qué comandos usarías? Probé el cómodo lsyfindcon los indicadores necesarios, pero eran muy lentos o generaban advertencias, por lo que creo que necesito un mejor sistema de archivos o db o algo así para indexar previamente las imágenes. Básicamente necesito una matriz en la que los inodes de las fotos se coloquen en orden cronológico. ¿Como hacer eso? Más tarde, se podrían agregar metadatos con marcas de tiempo unix.

[Actualizar]

Hay una falla grave en las respuestas actuales, la gente simplemente publica un tipo de respuestas sin pruebas empíricas. Si hubieran probado sus sugerencias, probablemente fracasarían. Por lo tanto, te creé una herramienta de línea de comandos mediante la cual puedes crear el sandbox para crear la gran cantidad de archivos y probar tus sugerencias como con 1e7 cantidad de archivos. Generar los archivos puede llevar mucho tiempo, así que tenga paciencia. Si alguien conoce una forma más rápida de hacerlo, edite el código. Escriba python code.py --helppara obtener la ayuda. ¡Que te diviertas!

Ejemplo de uso para crear muchos archivos dirigidos

$ ls ./data2
ls: ./data2: No such file or directory
$ python testFill.py -n 3 -d 7                                                 
$ tree data2/                                                                  
data2/
|-- 0
|   |-- 1302407302636973
|   |-- 1302407302638022
|   `-- 1302407302638829
|-- 1
|   |-- 1302407302639604
|   |-- 1302407302641652
|   `-- 1302407302642399
|-- 2
|   |-- 1302407302643158
|   |-- 1302407302645223
|   `-- 1302407302646026
|-- 3
|   |-- 1302407302646837
|   |-- 1302407302649110
|   `-- 1302407302649944
|-- 4
|   |-- 1302407302650771
|   |-- 1302407302652921
|   `-- 1302407302653685
|-- 5
|   |-- 1302407302654423
|   |-- 1302407302656352
|   `-- 1302407302656992
`-- 6
    |-- 1302407302657652
    |-- 1302407302659543
    `-- 1302407302660156

7 directories, 21 files

Código testFill.py

# Author: hhh
# License: ISC license

import os, math, time, optparse, sys

def createHugeAmountOfFiles(fileAmount, dirAmount):
   counter = 0
   DENSITY = 1e7
   dir = "./data/"

   do = dir+str(counter)+"/"
   while (os.path.exists(do)):
      counter = counter+1
      do = dir+str(counter)+"/"

   os.mkdir(do)

   for d in range(int(dirAmount)):
      for f in range(int(fileAmount)):
         timeIt = int(time.time()*1e6)
         if (not os.path.exists(do)):
            os.mkdir(do)

         if (timeIt % DENSITY == 0):
            counter = counter+1
            do = dir+str(counter)+"/"

            if (not os.path.exists(do)):
               os.mkdir(do)


         do = dir+str(counter)+"/"
         if(not os.path.exists(do)):
            os.mkdir(do)

         f = open(do+str(timeIt), 'w')
         f.write("Automatically created file to test Huge amount of files.")
         f.close()
      counter = counter +1


def ls(dir):
   for root, dirs, files in os.walk("./data/"+dir):
      print(files)

def rm(dir):
   for root, dirs, files in os.walk("./data/"+dir):
      for f in files:
         os.remove("./data/"+dir+"/"+f)


def parseCli():
   parser = optparse.OptionParser()
   parser.add_option("-f", "--file", dest="filename",
                     help="Location to remove files only in ./Data.", metavar="FILE")
   parser.add_option("-n", "--number", dest="number",
                     help="Number of files to generate", metavar="NUMBER")
   parser.add_option("-r", "--remove", dest="remove",
                     help="Data -dir content to remove", metavar="NUMBER")
   parser.add_option("-d", "--dir", dest="dir",
                     help="Amount of dirs to generate", metavar="NUMBER")
   parser.add_option("-q", "--quiet",
                     action="store_false", dest="verbose", default=True,
                     help="don't print status messages to stdout")

   return parser.parse_args()

def main():
   (options, args) = parseCli()

   if (options.filename):
      ls(options.filename)
   if (options.number and options.dir):
      createHugeAmountOfFiles(options.number, options.dir)
   if (options.remove):
      rm(options.remove)


main()
Kevin Bowen
fuente
2
@hhh para los conjuntos de datos en esta escala, una base de datos correctamente indexada es probablemente la única opción
xenoterracide
@xenoterracide: pero incluso dbs debe implementar una búsqueda rápida con algo como matrices, db suena demasiado. La fuente para tomar fotos está aquí: github.com/fsphil/fswebcam . Tal vez, podría modificarlo un poco el tiempo que guarda la imagen para poder agregar una línea con número de inodo y sello de tiempo unix al archivo. Ahora no con las imágenes sino con la línea, sería mucho más rápido buscar imágenes. O incluso más fácilmente, cada vez que se guarda una imagen en un disco, agrego una línea a un archivo de su sello de tiempo. Solución redonda. Pero no resolverá el problema con las imágenes actuales, así que pregunta si es relevante
@hhh ¿qué sistema de archivos estás usando? o eso no importa todavía ... ext sí ​​tiene algunas características para mejorar el rendimiento que pueden no estar activadas por defecto. Aunque incluso esos probablemente no tratarán en la escala de la que estás hablando. Los DB están optimizados para estas cosas y tienen varias soluciones de indexación para tratar con ellos. por ejemplo, un índice btree no es solo una simple matriz ...
xenoterracide
@xenoterracide: ext3, tampoco estoy seguro si importa. Creo que la solución que ilustré soluciona el problema para futuros problemas de búsqueda, pero no ayuda en absoluto con las fotos actuales, es muy lento buscarlo.
1
¿Tiene millones de archivos en un solo directorio? Si es así, puede considerar dividirlos en subdirecciones profundas de uno o dos niveles, según los primeros caracteres del nombre del archivo, por ejemplo:a/b/abcdef.jpg
alex

Respuestas:

4

Prueba con un caparazón diferente. Recomiendo probar zsh por ejemplo, y ver si permite más parámetros.

Si entiendo correctamente, parte del nombre de archivo, es una marca de tiempo UNIX. Puede ser aconsejable dividir los archivos en carpetas. Si el formato de fecha / hora es un número de época UNIX, coloque trozos de fracciones de ese número, digamos 10000, en una carpeta separada.

Si una marca de tiempo ISO 8601 es parte del nombre de archivo, simplemente divídala por año, mes o día.

polemon
fuente
1
ls y find no están integrados ni en bash ni en zsh, por lo que no está claro cómo cambiar los shells ayudaría en este caso.
Robin Green
Se trata de la expansión de shell. Si el shell no puede expandir el globbing, este podría ser el problema.
polemon
Hice algunas pruebas de ejecución de comandos en unos archivos 1E6, ZSH se enfrenta a los mismos problemas: "$ cp * Test/ ksh: cp: Argument list too long % rm * zsh: sure you want to delete all the files in /home/user/Downloads [yn]? y zsh: argument list too long: rm % ls * zsh: argument list too long: ls ". Lo siento, pero no puedo ver cómo se relaciona esto con la pregunta -1 porque fue muy fácil probar esto, crear solo archivos 1e6 y ejecutar los comandos.
1

¿Sería locate(y por supuesto updatedb) de alguna ayuda para usted?

asoundmove
fuente
1
updatedbusos find.
dave1010
@ dave1010, claro, pero lo hace en el fondo de vez en cuando, por lo que si es aceptable para el OP no necesariamente estar actualizado cada minuto, pero tal vez una vez al día, entonces programe la actualización b a una hora tranquila (o programar actualizadob con frecuencia pero con una prioridad baja, que es lo que debería ser de todos modos), luego usar localizar es muy rápido para encontrar lo que desea. Entonces, la pregunta clave es qué tan actualizada debe estar la base de datos (o el índice de cualquier otro sistema).
asoundmove