Encontrando blocos duplicados de texto dentro de um arquivo usando o shell script

0

Digamos que eu tenha um arquivo de texto com as seguintes linhas: -

abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}
abcd/efgh/a.jar
{
cdef/ghij/b.class
}

Agora, abcd / efgh / a.jar no primeiro caso tem abcd / efgh / a.class, cdef / ghij / b.class e klmn / opqr / c.class dentro das chaves. Considere isso como um bloco de texto. Agora abcd / efgh / a.jar abaixo novamente tem cdef / ghij / b.class dentro de chaves. Eu quero remover esta seção / bloco de texto. Então a saída final precisa ser como: -

abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}

Qualquer ajuda seria muito apreciada:)

    
por AJS 29.06.2017 / 07:35

3 respostas

2

Use

for i in 'awk '/}/ {if (NR!=1) print "";next} \
                {printf "%s ",$0,"}"}END{print ""}' yt.txt \
        |awk '{print $1}'|sort|uniq \
    '; \
    do \
        awk '/}/ {if (NR!=1) print "";next} \
            {printf "%s ",$0,"}"}END{printf ""} \
            ' yt.txt \
         |grep "$i"|sed 's/ /\n/g'|grep -v "$i"|sort|uniq \
            |awk -v var="$i" ' NR==1 {printf var} {print $0} END {print "}"}'  \
    ;done \

Mesmo comando em 1 linha abaixo (para fins de cópia)

for i in 'awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"}END{print ""}' yt.txt|awk '{print $1}'|sort|uniq' ; do awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"}END{printf ""}' yt.txt|grep "$i"|sed 's/ /\n/g'|grep -v "$i"|sort|uniq|awk -v var="$i" ' NR==1 {printf var} {print $0} END {print "}"}' ;done

Explicação:

A parte for retornará o título exclusivo do bloco ( abcd/efgh/a.jar , lkmn/opqr/b.zip ) e passará para o bloco do . A do parte primeiro grep todas as linhas de cada título, o que incluiria duplicatas também. Em seguida, excluirá o título e mesclará todas as linhas restantes sob esse título, depois adicionará o título na primeira linha. E codifique } no final.

Exemplo

bash-4.2$ cat yt.txt
abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}
abcd/efgh/a.jar
{
cdef/ghij/b.class
d.class
}



bash-4.2$ for i in 'awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"} \
> END{print ""}' yt.txt |awk '{print $1}'|sort|uniq' \
> ; do awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"}END{printf ""}' yt.txt \
>  |grep "$i"|sed 's/ /\n/g'|grep -v "$i"|sort|uniq \
> |awk -v var="$i" ' NR==1 {printf var} {print $0} END {print "}"}'\
> ;done
abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
d.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}
    
por 29.06.2017 / 10:04
1

Depois que vi a solução utilizando um loop for com awk e sort e uniq e grep e sed , tentei uma solução com uma ferramenta em vez de seis:

sed ':a
  N;$!ba
  y/\n_/_\n/;s/^/_/
  :b
  s/\(_[^_]*_{\)\([^}]*\)\(_[^_}]*\)\(_[^}]*\)\(_}.*\)\([^}]*\)_/_/;tb
  :c
  s/\(_[^_]*_{\)\([^}]*\)_}\(.*\)\([^}]*\)_}/_}/;tc
  s/^_//
  y/\n_/_\n/' yourfile

faz o trabalho, mas tenho que admitir que as expressões regulares são mais fáceis de escrever do que de ler ... (-;

    
por 29.06.2017 / 13:05
0
perl -alF'/\n[}{]\n/' -0777ne '
   for ( 0 .. $#F/2 ) {
      my $i = 2*$_;
      my($k,$v) = @F[$i,$i+1];
      if ( exists $h{$k} ) {
         $h{$k} .= join $\, grep { ! exists $seen{$k,$_} } split $\, $v;
      } else {
         push @k, $k;
         $seen{$k,$_}++ for split $\, $h{$k} = $v;
      }
   }
   print "$_\n{\n$h{$_}\n}" for @k;
' yourfile

Resultados

abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}

Trabalhando

O arquivo de entrada é sugado e dividido em campos com base no separador de campo mencionado pela opção -F . Nós estaremos recebendo um número par de elementos no array @F . Os pares numerados entao entao como as chaves do hash %h enquanto seus corresp. os valores são obtidos do próximo valor ímpar.

O hash %h é preenchido dividindo-se os elementos numerados ímpares no separador de registro ($ \ = \ n). Ao mesmo tempo, colocamos a chave na matriz @k para que possamos recuperar elementos hash na ordem em que foram encontrados.

Ao mesmo tempo, apenas aqueles elementos ímpares são usados e não são vistos.

    
por 01.07.2017 / 20:33