Descobrir se alguma linha de um arquivo é um subconjunto de dados em outro arquivo

4

Eu tenho um arquivo file1.txt com os seguintes dados:

MIME_HTML_ONLY
SUSPICIOUS_RECIPS
SORTED_RECIPS
HFILTER_HELO_5

e outro arquivo file2.txt com linhas como:

HFILTER_FROM_BOUNCE FORGED_OUTLOOK_HTML
SORTED_RECIPS HFILTER_HELO_5
MIME_HTML_ONLY HFILTER_FROM_BOUNCE
SUSPICIOUS_RECIPS ANY_OTHER_WORD
:
:

Eu quero encontrar todas as linhas em file2.txt who's data (todas as palavras dessa linha) é o subconjunto dos dados presentes em file1.txt

Por exemplo, a saída acima deve ser a linha: SORTED_RECIPS HFILTER_HELO_5

Agora posso percorrer e ler linhas individuais de file2.txt e ver se é o subconjunto de file1.txt . Mas eu tenho que fazer isso para dizer um 1000% diferentefile1.txt's. Então, percorrer linhas individuais de file2.txt para cada file1.txt é muito lento. Existe alguma maneira eficiente de fazer isso usando awk sed grep ?

    
por awhitesong 07.08.2015 / 01:55

2 respostas

3

O script a seguir está compilando file1.txt em uma única regex para grep -E .

#!/bin/sh
regex="^($(awk '{printf $0"|"}' $1) )+\$"
grep -E "$regex" $2

Uso:

$ ./script.sh file1.txt file2.txt 
SORTED_RECIPS HFILTER_HELO_5

$regex é compilado a partir de file1.txt da seguinte forma:

^(ME_HTML_ONLY|SUSPICIOUS_RECIPS|SORTED_RECIPS|HFILTER_HELO_5| )+$

Para milhares de file1.txt e file2.txt com milhões de linhas, seria melhor compilar todo o file1.txt's em um único programa awk com o seguinte script:

#!/bin/sh
for i; do
        regex="^($(awk '{printf $0"|"}' $i) )+\$"
        echo "/$regex/ { print \"$i: \"\
$ ./script2.sh match*.txt 
/^(ME_HTML_ONLY|SUSPICIOUS_RECIPS|SORTED_RECIPS|HFILTER_HELO_5| )+$/ { print "match1.txt: "$0 }
/^(HFILTER_FROM_BOUNCE|FORGED_OUTLOOK_HTML|ANY_OTHER_WORD| )+$/ { print "match2.txt: "$0 }
/^(SORTED_RECIPS|HFILTER_HELO_5|MIME_HTML_ONLY|HFILTER_FROM_BOUNCE| )+$/ { print "match3.txt: "$0 }

$ ./script2.sh match*.txt >match.awk
$ awk -f match.awk file2.txt 
match2.txt: HFILTER_FROM_BOUNCE FORGED_OUTLOOK_HTML
match1.txt: SORTED_RECIPS HFILTER_HELO_5
match3.txt: SORTED_RECIPS HFILTER_HELO_5
match3.txt: MIME_HTML_ONLY HFILTER_FROM_BOUNCE
}" done

Por exemplo, ( file1.txt's são nomeados como match1.txt match2.txt match3.txt ):

#!/bin/sh
regex="^($(awk '{printf $0"|"}' $1) )+\$"
grep -E "$regex" $2
    
por 07.08.2015 / 02:44
4
awk 'FNR == NR && $0 !~ /^[[:blank:]]*$/ { Dict[$0] = 1 }
     FNR != NR {
        i = 1
        while( i <= NF && Dict[ $i] == 1) i++
        if( i > NF) print
        }
    ' File1.txt File2.txt
  • genérico, não dependente do número do arquivo2 do campo / palavra por linha
  • trabalhe com conteúdo classificado e não classificado de ambos os arquivos
  • usa memória para carregar o primeiro arquivo em Dictionnary , então talvez não seja o melhor se um número enorme de palavras valida
  • pedido de arquivos para fornecer ao awk é obrigatório
    • 1a referência é dicionariedade
    • qualquer (pelo menos 1) outro arquivo para filtrar

Conceito:

  • carrega cada palavra em uma matriz usando o valor como índice
    • considerando 1 como valor (não atribuído tem 0 por padrão)
    • do primeiro arquivo [onde FNR (número de registro do arquivo) = NR (número do registro desde o primeiro arquivo aberto) e um registro é, por padrão, uma linha no awk]
    • há um filtro na linha vazia (sem caractere ou apenas espaço)
  • inicializa um contador (i)
  • compare cada campo (palavra aqui devido ao separador de espaço por padrão) ao seu equivalente em Dictionnary. Se existir (valor = 1), faça um loop para o próximo campo e incremente um contador (i)
  • após o loop, se o contador (i) for maior que o número de campo (word), todas as palavras são correspondentes, imprimimos a linha
  • loop para a próxima entrada de linha
por 07.08.2015 / 10:37