Wie verwalte ich eine große Anzahl von Dateien in der Shell?

9

$ ls ./dir_with_huge_amount_of_files/errors/

Angenommen, ein Verzeichnis ist voller Bilder mit Unix-Zeitstempeln. Ich meine viel gemessen in vielen GB oder sogar mehr. Shell-Befehle wie lserhalten Warnungen im Überlaufstil, da sie nicht für die Arbeit mit Millionen (oder mehr) Bildern ausgelegt sind. Wie kann ich so viele Dateien verwalten? Wenn ich zum Beispiel das Bild in der Mitte finden möchte (entsprechend dem Zeitstempel im Namen und der Erstellungszeit), gibt es ein Dateisystem, das eine integrierte Suchfunktion bietet? Welche Befehle würden Sie verwenden? Ich versuchte es bequem lsundfindmit den notwendigen Flags, aber sie waren entweder sehr langsam oder erzeugten Warnungen, also denke ich, dass ich entweder ein besseres Dateisystem oder eine bessere Datenbank oder ähnliches brauche, um die Bilder vorab zu indizieren. Ich brauche grundsätzlich ein Array, auf dem die Inodes der Fotos in chronologischer Reihenfolge angeordnet werden sollen. Wie geht das? Später könnten Metadaten mit Unix-Zeitstempeln hinzugefügt werden.

[Aktualisieren]

Die aktuellen Antworten weisen einen schwerwiegenden Fehler auf. Die Leute veröffentlichen nur Antworten ohne empirische Tests. Wenn sie ihre Vorschläge getestet hätten, würden sie wahrscheinlich scheitern. Daher habe ich Ihnen ein Befehlszeilentool erstellt, mit dem Sie die Sandbox erstellen können, um die große Anzahl von Dateien zu erstellen und Ihre Vorschläge wie mit 1e7 Dateien zu testen. Das Generieren der Dateien kann lange dauern. Seien Sie also geduldig. Wenn jemand einen schnelleren Weg kennt, bearbeiten Sie bitte den Code. Geben Sie ein python code.py --help, um die Hilfe zu erhalten. Habe Spaß!

Anwendungsbeispiel zum Erstellen vieler dirred-Dateien

$ 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
quelle
2
@hhh für Datensätze auf dieser Skala ist wahrscheinlich eine ordnungsgemäß indizierte
Datenbank
@xenoterracide: aber selbst dbs muss eine schnelle suche mit so etwas wie arrays implementieren, db klingt übertrieben. Die Quelle für das Fotografieren ist hier: github.com/fsphil/fswebcam . Vielleicht könnte ich es ein wenig modifizieren, wenn es das Bild speichert, damit ich eine Zeile mit Inode-Nummer und Unix-Zeitstempel an die Datei anhängen kann. Jetzt nicht mit den Bildern, sondern mit der Linie, wäre es viel schneller, nach Bildern zu suchen. Oder noch einfacher: Jedes Mal, wenn ein Bild auf einer Festplatte gespeichert wird, füge ich einer Datei mit ihrem Zeitstempel eine Zeile hinzu. Rundum-Lösung. Aber wird das Problem mit aktuellen Bildern nicht lösen, also frage relevant.
@hhh welches Dateisystem benutzt du? oder spielt das noch keine Rolle ... ext verfügt über einige leistungssteigernde Funktionen, die möglicherweise nicht standardmäßig aktiviert sind. Obwohl selbst diese wahrscheinlich nicht auf der Skala handeln, von der Sie sprechen. DBs sind für diese Dinge optimiert und verfügen über verschiedene Indexierungslösungen, um damit umzugehen. Zum Beispiel ist ein Btree-Index nicht nur ein einfaches Array ...
Xenoterracide
@xenoterracide: ext3, auch nicht sicher, ob es darauf ankommt. Ich denke, die Lösung, die ich illustriert habe, behebt das Problem für zukünftige Suchprobleme, aber es hilft bei aktuellen Fotos überhaupt nicht, es ist sehr zeitaufwändig, sie zu suchen.
1
Haben Sie Millionen von Dateien in einem einzigen Verzeichnis? Wenn ja, können Sie sie in ein oder zwei Ebenen tiefe Unterverzeichnisse aufteilen, basierend auf den ersten Zeichen des Dateinamens, z. B.:a/b/abcdef.jpg
Alex

Antworten:

4

Versuchen Sie es mit einer anderen Shell. Ich würde zum Beispiel empfehlen, zsh auszuprobieren und zu prüfen, ob mehr Parameter zulässig sind.

Wenn ich das richtig verstehe, ist ein Teil des Dateinamens ein UNIX-Zeitstempel. Es kann ratsam sein, die Dateien in Ordner zu unterteilen. Wenn das Datums- / Uhrzeitformat eine UNIX-Epochennummer ist, legen Sie Bruchteile dieser Zahl, z. B. 10000, in einem separaten Ordner ab.

Wenn ein ISO 8601- Zeitstempel Teil des Dateinamens ist, teilen Sie ihn einfach durch Jahr, Monat oder Tag.

Polemon
quelle
1
ls und find sind weder in bash noch in zsh integriert, daher ist unklar, wie das Wechseln von Shells in diesem Fall helfen würde.
Robin Green
Es geht um Shell-Erweiterung. Wenn die Shell das Globbing nicht erweitern kann, ist dies möglicherweise das Problem.
Polemon
Ich habe einige Tests durchgeführt, in denen Befehle für ungefähr 1e6-Dateien ausgeführt wurden. ZSH hat die gleichen Probleme : "$ 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 ". Entschuldigung, aber ich kann nicht sehen, wie dies mit der Frage -1 zusammenhängt, da es so einfach war, dies zu testen, nur 1e6-Dateien zu erstellen und die Befehle auszuführen.
1

Wäre locate(und natürlich updatedb) eine Hilfe für Sie?

asoundmove
quelle
1
updatedbverwendet find.
Dave1010
@ dave1010, klar, aber dies geschieht gelegentlich im Hintergrund. Wenn es für das OP akzeptabel ist, nicht unbedingt jede Minute, sondern möglicherweise einmal am Tag auf dem neuesten Stand zu sein, planen Sie die Aktualisierung zu einer ruhigen Stunde (oder Planen Sie regelmäßig aktualisiert, aber mit einer niedrigen Priorität (wie es ohnehin sein sollte). Dann ist es mit der Suche sehr schnell, das zu finden, was Sie wollen. Die entscheidende Frage ist also, wie aktuell die Datenbank (oder der Index für ein anderes solches System) sein muss.
Asoundmove