Imprimindo linhas de um arquivo se parte delas aparecer em outro. Ambos os arquivos são milhões de linhas

5

Eu tenho dois arquivos, vamos chamá-los de 123.txt e 789.txt . 123.txt tem 2,5 milhões de linhas e 789.txt tem 65 milhões de linhas. Existe alguma maneira de usar grep ou similar para manter as linhas de 789.txt que contêm linhas de 123.txt?

Haverá um máximo de uma duplicata por linha em 789.txt e o texto duplicado estará no início da linha. Eu estou totalmente preso a isso, e não consegui encontrar nenhuma informação online, então eu realmente não tenho nada para começar. Ele estará rodando em um servidor, então eu não me importo de demorar um pouco (o que eu sei que vai acontecer)

  • 123.txt:

    hxxp://www.a.com
    hxxp://www.b.com
    hxxp://www.c.com
    
  • 789.txt:

    hxxp://www.a.com/kgjdk-jgjg/
    hxxp://www.b.com/gsjahk123/
    hxxp://www.c.com/abc.txt
    hxxp://www.d.com/sahgsj/
    
  • Saída desejada:

    hxxp://www.a.com/kgjdk-jgjg/
    hxxp://www.b.com/gsjahk123/
    hxxp://www.c.com/abc.txt
    
por Joe 01.08.2013 / 18:07

2 respostas

12

Você pode fazer isso com muita facilidade usando grep :

$ grep -Ff 123.txt 789.txt
http://www.a.com/kgjdk-jgjg/ 
http://www.b.com/gsjahk123/ 
http://www.c.com/abc.txt 

O comando acima imprimirá todas as linhas do arquivo 789.txt que contém qualquer uma das linhas de 123.txt . O -f significa "leia os padrões para procurar neste arquivo" e o -F informa ao grep para tratar os padrões de busca como strings e não suas expressões regulares padrão.

Isso não funcionará se as linhas de 123.txt contiverem espaços à direita, grep tratará os espaços como parte do padrão para procurar um não corresponderá se ocorrer dentro de uma palavra. Por exemplo, o padrão foo (observe o espaço à direita) não corresponderá a foobar . Para remover espaços à direita do seu arquivo, execute este comando:

$ sed 's/ *$//' 123.txt > new_file

Em seguida, use o new_file para grep:

$ grep -Ff new_file 789.txt

Você também pode fazer isso sem um novo arquivo, usando o sinalizador i :

$ sed -i.bak 's/ *$//' 123.txt

Isso alterará o arquivo 123.txt e manterá uma cópia do original chamado 123.txt.bak .

(Observe que essa forma do -i flag para sed assume que você tem o GNU sed ; para o BSD sed use -i .bak com um espaço entre eles).

    
por 01.08.2013 / 18:31
4

Se os arquivos do seu exemplo forem classificados e sempre seguirem esse padrão, você poderá escrevê-lo:

join -t/ -1 3 -2 3 123.txt 789.txt |
  sed -n 's,\([^/]*/\)\([^/]*://\),,p'

Isso seria o mais eficiente.

    
por 01.08.2013 / 19:39