grep com muitos arquivos que contém muitas linhas?

4

Imagine que temos muitos arquivos enormes (30000 linhas): a.2014-05-06, a.2014-05-07, a.2014-05-08 e assim por diante.

Eu sei que podemos usar uma linha com a palavra usando este comando:

grep "word" a.*

Primeiro, acho que isso abrirá todos os arquivos e os fechará antes de abrir o segundo arquivo para procurar a palavra? isso é eficiente, se não há uma maneira mais eficiente?

Segunda Como determinar o arquivo no qual encontramos a palavra? por exemplo:
se a.2014-05-06 tiver:

a
bx
.
.

a.2014-05-07:

by
.
.

a.2014-05-08:

c
.
.

e fazemos o seguinte:

grep "b" a.*

a saída será:

bx
by

Eu quero uma saída assim:

bx  a.2014-05-06
by  a.2014-05-07
    
por Networker 12.08.2014 / 08:11

6 respostas

3

First I guess this will open every file and close it before opening the second file to search for the word? is this efficient, if not is there a way more efficient?

Sim, o grep será aberto e pesquisará todos os arquivos por vez. Na maioria das configurações, essa é a maneira mais eficiente. A menos que o regexp seja extremamente complexo, essa tarefa está firmemente vinculada à E / S, ou seja, o gargalo de desempenho está sendo lido no disco e sua CPU não será sobrecarregada.

Em algumas configurações, a E / S pode ser paralelizada; por exemplo, se você tiver uma configuração RAID-1 ou RAID-0, os dois (ou mais) componentes da matriz RAID poderão ser lidos em paralelo, o que economizará tempo. Se você tem essa configuração, você pode chamar uma ferramenta como GNU Parallel para chamar duas instâncias do grep (veja o manual para exemplos de comando). Na maioria das configurações, chamar duas instâncias de grep paralelamente será mais lento, porque as cabeças de disco continuarão alternando entre os arquivos acessados pelas duas instâncias (com SSD, chamar duas instâncias em paralelo normalmente não causará uma lentidão maior, mas ganhou seja mais rápido também.

Se você passar mais de um arquivo na linha de comando, o grep mostrará o nome do arquivo antes de cada correspondência, no formato

path/to/file:line containing a match

Se você estiver usando um padrão curinga ou alguma outra forma de gerar nomes de arquivo e quiser exibir o nome do arquivo mesmo no caso de haver um único arquivo correspondente, diga ao grep para pesquisar o vazio dispositivo nulo também.

grep REGEX /dev/null *.txt

( grep -H REGEX *.txt é semelhante, mas usar /dev/null tem o benefício adicional de funcionar perfeitamente, mesmo se a lista de arquivos correspondentes estiver vazia, enquanto grep -H REGEX lê a entrada padrão.)

    
por 13.08.2014 / 02:58
5

Em man grep :

       -H, --with-filename
           Print the file name for each match.  This is the default when there is
           more than one file to search.

Ele imprimirá o nome do arquivo primeiro, seguido da correspondência; que não é o que você mostrou nos resultados do seu exemplo. Mas é rápido e fácil se isso não causar um problema.

Como é padrão para mais de uma entrada, usá-la com um caractere curinga (como no seu exemplo) resulta em:

$ grep "b" a.*
a.2014-05-06:bx
a.2014-05-07:by

Você não mencionou qual sabor do Unix / Linux está usando, mas a opção -H está disponível na maioria das implementações, embora não esteja na especificação POSIX.

    
por 12.08.2014 / 09:26
3

Para pesquisar um disco sem abrir todos os arquivos:

dd if=/dev/${disk_device} |
grep -b 'some regex'

Na verdade, gosto muito disso:

sudo cat /dev/${some_disk} |
tr -c '[:print:][:space:]' '\n\n' |
grep -b 'some regex'

A opção -b fornecerá os deslocamentos de bytes para todas as correspondências. Você pode verificar posteriormente com o sistema de arquivos quais arquivos existem nesses deslocamentos.

No segundo formulário você evita grep reclamando sobre tipos de arquivos binários AND automaticamente acelera sua busca, fornecendo novas linhas no lugar de dados irrelevantes.

P.S. - Se o seu sistema de arquivos puder ser desfragmentado, pode ser uma boa ideia fazer isso primeiro.

    
por 13.08.2014 / 04:48
1

Use perl :

perl -nle 'print "$1 $ARGV" if /(pattern)/' a.*

E, para sua pergunta, sim, grep abra cada arquivo para pesquisa, feche-o, abra o próximo arquivo e assim por diante.

$ strace -e trace=file,close grep Power 1.txt 2.txt
....
openat(AT_FDCWD, "1.txt", O_RDONLY)     = 3
1.txt:Power and signal 
1.txt:VDD Digital Power This pin provides power supply connection for the digital
1.txt:VMEASPOS Digital Power Voltage to be measured.
1.txt:VREFEXT Digital Power Reference voltage input of 1.024V %for VSENS calibration.
close(3)                                = 0
openat(AT_FDCWD, "2.txt", O_RDONLY)     = 3
2.txt:0.078362 Power
2.txt:Power
close(3)

Eu não posso pensar em uma maneira melhor de fazer isso. Quase ferramentas de processamento de texto também se comportam assim. A única diferença que posso ver é qual chamada de sistema eles usam. grep use openat () , enquanto perl , awk use open () .

    
por 12.08.2014 / 08:21
1

Duas outras coisas para ter em mente quando grep -ing em arquivos grandes (ou muitos):

  1. Se você estiver procurando por uma string fixa em vez de um padrão, adicione a opção -F a grep , isso acelerará sua pesquisa tremendamente (consulte Source )

  2. Se você souber que está realmente procurando uma palavra, ou seja, seu padrão de pesquisa é delimitado por caracteres que não são de palavras ou início / fim da linha, adicione a opção -w . Isso vai acelerar a pesquisa, eu acho.

por 14.08.2014 / 09:37
1

Esta é uma resposta 'alternativa' para sua pergunta. Eu pensei sobre o comentário por um tempo, mas no final decidi que poderia ser uma resposta para alguns. Também parece muito longo para um comentário legível.

Se o seu objetivo é pesquisar um monte de arquivos para uma string de uma forma mais rápida e, em seguida, encontrar grep muito lento, você pode tentar git grep . Requer que o git seja instalado e que um repositório seja criado.

Acho que isso parece ser mais rápido e fácil de usar.

git é um sistema de controle de versão distribuído. Ele também possui um recurso como git grep [string] para a pesquisa, que acho ser muito rápido. Eu acredito que isso pode ser por causa da maneira como os dados são indexados e armazenados.
Obtenha o git no link
Downloads para Mac / Linux / Windows / Solaris em link

Você pode criar um repositório git para um projeto atual simplesmente digitando git init na pasta raiz.

Uma vez feito, você pode digitar git grep [string]

    
por 14.08.2014 / 14:34