Como gerenciar uma grande quantidade de arquivos no shell?

9

$ ls ./dir_with_huge_amount_of_files/errors/

Suponha que um diretório esteja cheio de imagens com registros de data e hora unix, ou seja, muito medido em muitos GB ou mais. Comandos de shell como lsreceberão avisos no estilo de estouro porque não foram projetados para funcionar com milhões (ou mais) de imagens. Como posso gerenciar uma quantidade tão grande de arquivos? Se, por exemplo, eu quero encontrar a imagem no meio (de acordo com o registro de data e hora no nome e na hora da criação), existe algum sistema de arquivos que ofereça um recurso de pesquisa interno? Quais comandos você usaria? Eu tentei o confortável lsefindcom sinalizadores necessários, mas eles eram muito lentos ou geravam avisos, então estou pensando que preciso de um sistema de arquivos ou db melhor ou algo parecido para pré-indexar as imagens. Basicamente, preciso de uma matriz na qual os inodes das fotos sejam colocados em ordem cronológica. Como fazer isso? Posteriormente, metadados com timestamps unix podem ser adicionados.

[Atualizar]

Há uma falha séria nas respostas atuais, as pessoas simplesmente postam o tipo de respostas sem testes empíricos. Se eles tivessem testado suas sugestões, provavelmente fracassariam. Por isso, criei para você uma ferramenta de linha de comando pela qual você pode criar a sandbox para criar uma enorme quantidade de arquivos e testar suas sugestões, como na quantidade 1e7 de arquivos. Pode levar muito tempo para gerar os arquivos, portanto seja paciente. Se alguém souber a maneira mais rápida de fazer isso, edite o código. Digite python code.py --helppara obter ajuda. Diverta-se!

Exemplo de uso para criar muitos arquivos direcionados

$ 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
fonte
2
@hhh para conjunto de dados de nesta escala um db adequadamente ed-índice é provavelmente a única opção
xenoterracide
@xenoterracide: mas mesmo o dbs deve implementar a pesquisa rápida com algo como matrizes, o db soa um exagero. A fonte da coisa para tirar fotos está aqui: github.com/fsphil/fswebcam . Talvez eu possa modificá-lo um pouco o tempo que salva a imagem para poder acrescentar uma linha com número de inode e carimbo de hora unix ao arquivo. Agora, não com as imagens, mas com a linha, seria muito mais rápido procurar imagens. Ou ainda mais facilmente, cada vez que uma imagem é salva em um disco, anexo uma linha a um arquivo com seu carimbo de data / hora. Solução completa. Mas não vai resolver o problema com as fotos atuais, então questione relevante.
@hhh que sistema de arquivos você está usando? ou isso ainda não importa ... ext tem alguns recursos de aprimoramento de desempenho que podem não estar ativados por padrão. Embora mesmo aqueles que provavelmente não vão lidar com a escala que você está falando. Os bancos de dados são otimizados para essas coisas e têm várias soluções de indexação para lidar com elas. por exemplo, um índice btree não é apenas uma matriz simples ...
xenoterracide
@xenoterracide: ext3, não tenho certeza nem se importa. Eu acho que a solução que ilustrei corrige o problema para um problema de pesquisa futura, mas não ajuda em nada nas fotos atuais, é muito demorado pesquisá-lo.
11
Você tem milhões de arquivos em um único diretório? Nesse caso, considere dividi-las por subdiretórios profundos de um ou dois níveis, com base nos primeiros caracteres do nome do arquivo, por exemplo:a/b/abcdef.jpg
alex

Respostas:

4

Tente um shell diferente. Eu recomendaria tentar o zsh, por exemplo, e ver se ele permite mais parâmetros.

Se bem entendi, parte do nome do arquivo é um carimbo de data e hora do UNIX. Pode ser aconselhável dividir os arquivos em pastas. Se o formato de data / hora for um número de época do UNIX, coloque pedaços de frações desse número, digamos 10000, em uma pasta separada.

Se um carimbo de data / hora ISO 8601 fizer parte do nome do arquivo, simplesmente divida por ano, mês ou dia.

polemon
fonte
11
sl e find não são embutidos no bash ou no zsh, portanto, não está claro como a troca de shells ajudaria nesse caso.
Robin Green
É sobre expansão de shell. Se o shell não puder expandir o globbing, esse pode ser o problema.
Polemon
Eu fiz alguns testes executar comandos em cerca de 1E6 arquivos, ZSH enfrenta os mesmos 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 ". Desculpe, mas não consigo ver como isso está relacionado à pergunta -1, porque foi muito fácil testar isso, crie apenas arquivos 1e6 e execute os comandos.
1

Seria locate(e é claro updatedb) de alguma ajuda para você?

asoundmove
fonte
11
updatedbusos find.
dave1010
@ dave1010, claro, mas o faz em segundo plano de vez em quando, por isso, se é aceitável que o OP não esteja sempre atualizado a cada minuto, mas talvez uma vez por dia, programe a atualização em uma hora tranquila (ou agende atualizado com freqüência, mas com baixa prioridade, que é o que deve ser de qualquer maneira), e usar o find é muito rápido para encontrar o que você deseja. Portanto, a questão principal é a atualidade do banco de dados (ou do índice de qualquer outro sistema).
asoundmove