Comparando duas linhas no BASH usando o awk

0

Eu tenho um arquivo de texto como este.

2015-11-24 12:59:37.112 128.206.6.136 source
2014-11-24 12:59:36.920 8.8.8.8 source
2014-11-24 14:59:38.112 23.234.22.106 destination
2014-11-24 13:59:37.113 23.234.22.106 source
2014-11-24 12:59:29.047 74.125.198.141 source
2014-12-25 12:59:36.920 74.125.198.148 destination

Se um determinado endereço IP for marcado como origem e destino, quero marcá-lo como ambos . Neste caso, o Ip 23.234.22.106 é fonte assim como destino. Então, quero marcá-lo como ambos .

Meu resultado desejado deve ser assim

2015-11-24 12:59:37.112 128.206.6.136 source
2014-11-24 12:59:36.920 8.8.8.8 source
2014-11-24 14:59:38.112 23.234.22.106 both
2014-11-24 12:59:29.047 74.125.198.141 source
2014-12-25 12:59:36.920 74.125.198.148 destination

Isso é o que eu tentei.

cat input.txt | awk '{print $3}' | sort | uniq | while read line

do 
grep $line input.txt | sort -r -k1 | head -1
done

Mas, eu não entendo como marcar um Ip em particular como ambos se for fonte assim como destino. Neste caso, 23.234.22.106.

Como posso fazer isso usando o awk? Qualquer ajuda com isso seria apreciada. Obrigado

    
por Swatesh Pakhare 01.06.2016 / 20:03

2 respostas

5

Tente com sed

sed '
    N    #add next line
    s/\([0-9.]\+\)\s\S\+\n.*\s\s\S\+$/ both/
    P    #print first line from two
    D    #remove first line, return to start
    ' input.txt
  • [0-9.]\+ grupo de números e pontos
  • \s espaço ou guia
  • \S\+ grupo de símbolos não espaciais
  • \n nova linha
  • .* quaisquer símbolos
  • de referência para o grupo em parethesis \(...\)
  • $ padrão final

(modificado: remova o comando t (tnx 2 jthill ) e adicione \ espaço antes do grupo para verificar endereço completo)

    
por 01.06.2016 / 20:33
0

com perl :

#! /usr/bin/perl

use strict;

my @lines=();

while(<>) {
  chomp;
  s/#.*//g;        # strip comments
  s/^\s*|\s*$//g;  # strip leading and trailing spaces
  next if (/^$/);  # skip blank lines

  if (! scalar @lines) {
    # store the first line of the file in the array
    # we can't do anything else yet, so skip to the next line.
    push @lines, $_;
    next;
  } else {
    push @lines, $_;

    # split both lines into space-separated fields.
    my @a = split /\s+/, $lines[0];
    my @b = split /\s+/, $lines[1];

    # if 3rd fields are the same, change to "both"
    if ($a[2] eq $b[2]) {
      @lines = map { $_ =~ s/(source|destination)$/both/oi; $_} @lines;
    }
  }
  print $lines[0],"\n";
  shift @lines;
}
print $lines[0],"\n";

A ideia aqui é usar uma matriz ( @lines ) para manter a linha atual e a linha anterior. Se o 3º campo (arrays-perl são baseados em zero) de ambas as linhas for o mesmo, então altere as strings "source" ou "destination" para "both".

Imprima a linha anterior, tenham elas sido alteradas ou não. Em seguida, exclua a linha anterior da matriz, usando shift para que, na próxima passagem pelo loop, a linha atual seja a linha anterior.

Finalmente, depois que o loop terminar, imprima a última linha de entrada.

Saída:

$ ./swatesh.pl <swatesh.txt 
2015-11-24 12:59:37.112 128.206.6.136 source
2014-11-24 12:59:36.920 8.8.8.8 source
2014-11-24 14:59:38.112 23.234.22.106 both
2014-11-24 13:59:37.113 23.234.22.106 both
2014-11-24 12:59:29.047 74.125.198.141 source
2014-12-25 12:59:36.920 74.125.198.148 destination

Algumas notas:

O script sed funciona bem, então por que você pode optar por usar perl ? Quais são as diferenças?

@Costas ' sed version é mais rápido, o que pode ser significativo se você tiver milhões de linhas para processar.

Esta versão perl verifica explicitamente se o campo 3 em ambas as linhas é exatamente o mesmo, enquanto a versão sed só verifica se um padrão semelhante a um endereço IP é repetido mais tarde no mesmo conjunto duplicado line (que não é necessariamente um problema - para sua entrada de exemplo, a versão sed funciona perfeitamente. É otimizada para exatamente sua amostra).

A versão perl é provavelmente mais fácil de se adaptar a diferentes entradas.

O código no início do loop é um código útil que uso em muitos scripts perl para ignorar linhas em branco e para suportar # comentários em arquivos de texto. Eu costumo fazer o mesmo em sed scripts, mas quanto mais tempo um script sed se torna, menos legível é ... e eu gosto de escrever código que eu possa entender de relance em 6 meses.

Além desses detalhes relativamente pequenos, ambos os scripts usam um algoritmo muito semelhante.

    
por 02.06.2016 / 09:12