Pesquisa entre o conteúdo de um grande número de arquivos de texto simples?

3

Eu tenho um diretório com 1.242.276 arquivos de texto simples no meu disco rígido externo. Eles são totalmente desorganizados com números sem sentido como seus nomes de arquivos. A razão para isso é porque eles foram recuperados por algum software de recuperação após acidentalmente esvaziar uma partição há algum tempo.

Agora estou nesse diretório e quero pesquisar uma palavra "poliedro" entre o conteúdo de todos os arquivos. Eu tentei grep , mas isso falha:

$ grep polyhedron ./* 
bash: /bin/grep: Argument list too long

É porque existem muitos arquivos nesse diretório? Também gostaria de procurar muitas outras palavras-chave diferentes. Eu me pergunto o que posso fazer agora?

    
por Tim 15.12.2012 / 17:37

5 respostas

9

find . -type f -print0 | xargs -0 grep polyhedron

Dado que você provavelmente quer fazer algo como copiar os arquivos com a correspondência do termo em uma pasta com nomes semelhantes ...

find . -type f -print0 | xargs -0 grep -l polyhedron | while read i; do cp "$i" ../polyhedron; done

Se você sabe que não há sobreposição entre as correspondências de termos (ou seja, nenhum arquivo único teria 'poliedro' e outro termo que você deseja organizar), você pode mover mv em vez de copiar cp . / p>     

por 15.12.2012 / 18:26
7

Não há muitos arquivos, mas a lista de argumentos para o comando grep é muito longa. É uma limitação da chamada do sistema execve(2) no tamanho combinado da lista de argumentos e lista de variáveis de ambiente transmitidas ao longo dessa chamada.

No Linux, desde 2.6.23, é um limite administrativo que pode ser aumentado ou elevado usando ulimit -s (também define o limite no tamanho da pilha do processo). Então

ulimit -s unlimited

pode funcionar para você.

Caso contrário, soluções alternativas, a maioria das quais já mencionadas em outras respostas, consistem em dividir a lista de argumentos para que ela se encaixe nessa limitação ou evitar passar a lista de arquivos para execve .

ls | xargs grep polyhedron

(OK apenas porque os nomes dos arquivos contêm apenas dígitos)

(É responsabilidade do xargs dividir a lista e executar quantos comandos grep , conforme necessário, para que a limitação execve não seja atingida).

find . -exec grep polyhedron {} +

O mesmo, mas, desta vez, find faz a divisão.

grep -r polyhedron .

(se o seu grep suportar -r ), desta vez, apenas 3 args de alguns caracteres passaram para grep , é grep que constrói a lista de arquivos internamente e nunca os transmite para uma chamada de sistema execve.

Algumas shells têm suporte para .

Com shells em que grep está embutido, você não teria o problema, já que os buildins não são executados com uma chamada de sistema execve .

Com o ksh93, você pode usar:

command -x grep polyhedron *

E ksh93 fará a divisão.

zsh tem o comando zargs :

zargs * -- grep polyhedron

Para pesquisar mais de uma palavra, você pode fazer:

grep -e word1 -e word2 ...

Ou

grep 'word1
word2
...' ...

Ou coloque a lista de palavras em um arquivo, uma por linha e use

grep -f that-file ...
    
por 15.12.2012 / 21:49
5

Is it because there are too many files under that directory?

Sim. Você usa uma expansão curinga. Isso é todos os seus nomes de arquivos são expandidos na linha de comando. Isso falha porque há um limite de comprimento. Para determinar esse limite, tente:

getconf ARG_MAX

Also I would like to search for many other different keywords. I wonder what I can do now?

Já experimentou o modo recursivo grep?

grep -r polyhedron .

Existem também algumas outras abordagens, como mostram as outras respostas. Este artigo também oferece algumas informações sobre o problema e mais alguns exemplos sobre como contornar esta limitação de comprimento.

Copiei alguns dos exemplos aqui para dar uma ideia:

usando find :

find /nas/data/accounting/ -type f -exec ls -l {} \;

usando xargs :

echo /nas/data/accounting/* | xargs ls -l

usando um loop while:

find /nas/data/accounting/ -type f |
  while read file
  do
    mv /nas/data/accounting/$file /local/disk/
  done
    
por 15.12.2012 / 20:38
4

É precisamente esse o caso. Existem soluções alternativas para esse problema.

Resposta rápida para o problema do grep

find . -type f -exec grep -H polyhedron {} +

A longo prazo, sugiro que você use uma função para classificar os arquivos por tamanho (por exemplo) para poder trabalhar em partes menores de seus arquivos. Você pode usar este script:

#!/bin/sh
cd $1
files='find . -maxdepth 1 -type f'
for i in $files; do
    folder='du -k $i | cut -f1'
    mkdir $folder
    mv $i $folder/
done;

Tudo o que você precisa fazer é salvá-lo e executá-lo com:

sh <name of the script> <folder with all your files>

Opcionalmente, você pode adicionar permissões de execução para evitar a parte sh.

    
por 15.12.2012 / 18:34
2

Você pode tentar:

find . -print0|xargs -0 grep 'term1\|term2'

xargs irá gerar comandos mulitple grep usando seus argumentos máximos padrão. Se você ainda receber um erro "Argument list too long" de grep , poderá usar a opção --max-args para xargs .
O -print0 e -0 fazem com que use nomes de arquivos terminados com nulo para manipular nomes de arquivos com espaços.
Você pode pesquisar vários termos usando \| .
Há muitos arquivos, por isso, talvez você queira procurar maneiras de otimizar grep .

    
por 15.12.2012 / 18:24

Tags