Comment gérer une énorme quantité de fichiers dans le shell?

9

$ ls ./dir_with_huge_amount_of_files/errors/

Supposons qu'un répertoire soit plein d'images avec des horodatages Unix, je veux dire beaucoup mesuré en plusieurs Go ou même plus. Les commandes shell comme celles- lsci recevront des avertissements de type débordement car elles ne sont pas conçues pour fonctionner avec des millions (ou plus) d'images. Comment gérer une telle quantité de fichiers? Si, par exemple, je veux trouver l'image au milieu (en fonction de l'horodatage du nom et de l'heure de création), y a-t-il un système de fichiers qui offre une fonction de recherche intégrée? Quelles commandes utiliseriez-vous? J'ai essayé le confortable lsetfindavec les drapeaux nécessaires mais ils étaient soit très lents, soit des avertissements générés, donc je pense que j'ai besoin d'un meilleur système de fichiers ou d'une base de données ou quelque chose comme ça pour pré-indexer les images. J'ai essentiellement besoin d'un tableau dans lequel les inodes des photos doivent être placés dans l'ordre chronologique. Comment faire ça? Plus tard, des métadonnées avec des horodatages Unix pourraient être ajoutées.

[Mise à jour]

Il y a une faille sérieuse dans les réponses actuelles, les gens ne font que poster des sortes de réponses sans tests empiriques. S'ils avaient testé leurs suggestions, ils échoueraient probablement. Par conséquent, je vous ai créé un outil en ligne de commande par lequel vous pouvez créer le bac à sable pour créer une énorme quantité de fichiers et tester vos suggestions comme avec une quantité de 1e7 de fichiers. La génération des fichiers peut prendre beaucoup de temps, alors soyez patient. Si quelqu'un sait comment le faire plus rapidement, veuillez modifier le code. Tapez python code.py --helppour obtenir de l'aide. S'amuser!

Exemple d'utilisation pour créer un grand nombre de fichiers dirred

$ 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

Code 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
la source
2
@hhh pour les ensembles de données à cette échelle, une base de données correctement
indexée
@xenoterracide: mais même dbs doit implémenter une recherche rapide avec quelque chose comme des tableaux, db semble exagéré. La source pour la prise de vue est ici: github.com/fsphil/fswebcam . Peut-être que je pourrais le modifier un peu le temps qu'il enregistre l'image afin que je puisse ajouter une ligne avec le numéro d'inode et l'horodatage Unix au fichier. Maintenant, pas avec les images mais avec la ligne, il serait beaucoup plus rapide de rechercher des images. Ou encore plus facilement, chaque fois qu'une image est enregistrée sur un disque, j'ajoute une ligne à un fichier de son horodatage. Solution complète. Mais ne résoudra pas le problème avec les images actuelles, la question est donc pertinente.
@hhh quel système de fichiers utilisez-vous? ou cela n'a-t-il pas encore d'importance ... ext a des fonctionnalités d'amélioration des performances qui peuvent ne pas être activées par défaut. Même si ceux-ci ne fonctionneront probablement pas à l'échelle dont vous parlez. Les bases de données sont optimisées pour ces choses et disposent de diverses solutions d'indexation pour y faire face. par exemple, un index btree n'est pas seulement un simple tableau ...
xenoterracide
@xenoterracide: ext3, je ne sais pas non plus si cela importe. Je pense que la solution que j'ai illustrée résout le problème pour les futurs problèmes de recherche, mais cela n'aide pas du tout avec les photos actuelles, il faut beaucoup de temps pour les rechercher.
1
Avez-vous des millions de fichiers dans un seul répertoire? Si c'est le cas, vous pourriez envisager de les diviser en sous-répertoires profonds à un ou deux niveaux, en fonction des premiers caractères du nom de fichier, par exemple:a/b/abcdef.jpg
alex

Réponses:

4

Essayez un autre shell. Je recommanderais d'essayer zsh par exemple, et voir s'il autorise plus de paramètres.

Si je comprends bien, une partie du nom de fichier est un horodatage UNIX. Il peut être conseillé de diviser les fichiers en dossiers. Si le format de date / heure est un nombre d'époque UNIX, placez des morceaux de fractions de ce nombre, disons 10000, dans un dossier séparé.

Si un horodatage ISO 8601 fait partie du nom de fichier, divisez simplement par année, mois ou jour.

polémon
la source
1
ls et find ne sont pas intégrés dans bash ou zsh, donc on ne sait pas comment la commutation des shells aiderait dans ce cas.
Robin Green
Il s'agit de l'expansion du shell. Si le shell ne peut pas étendre le globbing, cela pourrait être le problème.
polemon
J'ai fait quelques tests en cours d' exécution des commandes sur environ 1E6 fichiers, ZSH fait face aux mêmes problèmes: "$ 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 ". Désolé mais je ne vois pas comment cela est lié à la question -1 car il était si facile de tester cela, de créer uniquement des fichiers 1e6 et d'exécuter les commandes.
1

Serait locate(et bien sûr updatedb) d'une quelconque aide?

asoundmove
la source
1
updatedbutilise find.
dave1010
@ dave1010, bien sûr, mais il le fait en arrière-plan de temps en temps, donc s'il est acceptable pour l'OP de ne pas nécessairement être à jour toutes les minutes, mais peut-être une fois par jour, alors programmez updatedb à une heure calme (ou programme mis à jour fréquemment mais avec une faible priorité, ce qui devrait être le cas de toute façon), puis l'utilisation de Locate est très rapide pour trouver ce que vous voulez. La question clé est donc de savoir à quel point la base de données (ou l'index de tout autre système de ce type) doit être à jour.
asoundmove