grep sai devido ao uso do RAM - posso fazer o grep não usar tanto o ram?

2

Eu tive uma operação que funciona através do originallist (dowork.sh originallist), e permite que você saiba o que foi concluído em clean1. O clean1 é classificado de forma diferente do originallist. Eu preciso gerar uma lista do que resta para o dowork.sh processar. Essencialmente: list cleanedR - list cleaned1 = list cleaned2. É uma operação negativa. Eu descobri que posso fazer essa operação com as seguintes opções do grep:

  • F para correspondência de linha completa em vez de expressão regular (não queremos que o grep surja com caracteres de nome de arquivo pensando que são expressões regulares)
  • v para excluir (que é a operação menos),
  • f para procurar pelo arquivo cleaned1 para as expressões em vez de uma única expressão dada ("obter PATTERN from FILE").
# wc -l cleaned*
 9157094 cleaned1
 14283591 cleanedR

# du -sh cleaned*
1.3G    cleaned1
2.0G    cleanedR

# grep -Fvf cleaned1 originallist > cleaned2

é executado por 5 minutos, consome até 42G de RAM ou menos, mas muito disso, depois sai com falha; O clean2 tem 0 bytes de comprimento.

cleaned2 no final deve ser 14283591 - 9157094 = 5126497 linhas longas

Esta é a sintaxe correta para fazer tal operação (eu testei com uma limpeza de 10 linhas de comprimento R e uma limpeza de 3 linhas de comprimento1; a limpeza resultante2 foi de 7 linhas), no entanto ele usa um monte de memória ram. Existe uma maneira de fazer esse trabalho fazendo com que o grep não use tanto ram? Eu sei que vai demorar um pouco, mas eu estou bem com isso.

Estou procurando algo como a opção -t do tipo sort, que permite que você não use up / tmp (ram no meu caso) e permite que você use outro diretório

sort -h
 -T, --temporary-directory=DIR  use DIR for temporaries, not $TMPDIR or /tmp;
                                multiple options specify multiple directories
    
por kossboss 16.08.2017 / 01:42

1 resposta

4

O comando sort tem algum suporte específico para trabalhar com enormes conjuntos de dados, porque esse é um caso de uso relativamente comum. Enormes padrões grep são um caso de uso extremamente incomum, então você não pode esperar que os desenvolvedores tenham se esforçado muito nisso.

Se a ordem das linhas não for importante, você poderá classificar os dois arquivos, após o que poderão ser comparados sem armazenar mais do que algumas linhas na memória por vez, independentemente do tamanho dos arquivos. Como o sort pode lidar com arquivos que não cabem na memória, isso é eficiente.

sort originallist >originallist.sorted
sort cleaned1 | comm -23 originallist.sorted - >cleaned2.sorted

Se a ordem original de originalistist importa, você pode adicionar números de linha a ela:

nl -w 22 originallist >originallist.numbered
# then generate cleaned1 from the numbered list

Como originallist.numbered está classificado, você pode executar comm para detectar linhas comuns.

Se o pedido é importante e é muito tarde para numerar as linhas, você pode tentar dividir cleaned1 em partes e fazer uma passagem em originallist para cada bloco. Com uma divisão recente do GNU:

cp originalfile cleaned2.in
split -l 1000000 --filter='grep -Fxv -f - cleaned2.in >cleaned2.out; mv cleaned2.out cleaned2.in' cleaned1
mv cleaned2.out cleaned2

(Observe que F não faz "correspondência de linha completa", ele faz uma correspondência de substring. Para uma correspondência de cadeia de linha completa, você precisa de -x também.)

    
por 17.08.2017 / 00:51

Tags