Remova todas as linhas, exceto D

4

Eu tenho um cenário em que meus três arquivos enormes Test.txt , Test1.txt e Test2.txt têm os detalhes a seguir.

H|||||||||||||||||||||||
D||||||||||||||||||||||||
D|||||||||||||||||||||||
H|||||||||||||||||||||
D||||||||||||||||||||||||
D||||||||||||||||||||||||
T||||||||||||||||||||||||

Eu tenho que excluir todos, exceto as linhas D. Ele deve se parecer abaixo em todos os meus três arquivos (mais de 10 GB)

D||||||||||||||||||||||||
D|||||||||||||||||||||||
D||||||||||||||||||||||||
D||||||||||||||||||||||||

Então, depois de manter apenas as linhas de D em Test.txt , Test2.txt e Test3.txt , Eu tenho que mesclá-los em novo arquivo.

Eu fiz a operação acima usando sed.

sed '/^\('D'\)|/!d' $Filename.txt >>  $NewFilename.txt

Mas por causa de arquivos enormes, é muito demorado.

Podemos fazer esta operação usando qualquer outro comando de maneira eficiente?

    
por UNIXbest 23.08.2013 / 07:39

2 respostas

13
cat Test.txt Test2.txt Test3.txt | LC_ALL=C grep '^D' > newfile.txt

Ou:

for file in Test.txt Test2.txt Test3.txt; do
  LC_ALL=C grep '^D' < "$file"
done > newfile.txt

Ou se o seu grep como o GNU grep suportar a opção -h (para evitar a impressão de nomes de arquivos):

LC_ALL=C grep -h '^D' Test.txt Test2.txt Test3.txt > newfile.txt

Ao usar LC_ALL=C , evitamos grep tentando analisar dados UTF-8. Ao usar ^D , grep apenas examinará o primeiro caractere de cada linha. grep , especialmente o GNU grep é geralmente muito mais rápido que sed .

    
por 23.08.2013 / 10:12
3

Isso provavelmente será uma operação de vinculação de E / S (em oposição a limite de CPU), portanto, mesmo que você não use um mecanismo de regexp como:

grep -F 'D|' Test.txt Test2.txt Test3.txt

demorará muito tempo, simplesmente porque o arquivo deve ser convertido em linhas e depois verificado quanto ao padrão.

Se isso é uma coisa única e você não se importa de codificar, você pode mmap(3) o arquivo inteiro na memória e usar memmem(3) :

char *p;
if ((p = memmem(file, size, "\nD|", 3)) != NULL) {
        /* massage the line, i.e. find the next '\n'
         * and print the region between p+1 and the
         * next '\n' */
}

em que file é o ponteiro para o buffer mmap e size é o tamanho do arquivo. (Se isso for útil, ficarei feliz em elaborar mais).

Essa abordagem ainda levará algum tempo (já que seu problema é limitado por E / S), mas pelo menos você economizaria tempo para transformar o arquivo em linhas.

    
por 23.08.2013 / 08:18