Команда Awk для объединения строк и их суммирования

#linux #scripting #awk

#linux #создание сценариев #awk

Вопрос:

Это формат, который у меня есть.

 Source IP       Destination IP    Received Sent
192.168.0.1     10.10.10.1        3412     341
192.168.0.1     10.10.10.1        341      43
192.168.0.1     10.22.22.2        34       334
192.168.0.1     192.168.9.3       34       243
  

Но это очень большой файл. В основном я хочу указать общую пропускную способность каждого IP-адреса источника. Итак, мне нужно объединить все исходные IP-адреса uniq, а затем добавить полученные столбцы всего, что уникально, а затем добавить отправленные столбцы. Конечным результатом было бы:

ip-адрес источника — общее количество полученных пакетов — общее количество отправленных пакетов

Также было бы неплохо унифицировать IP-адреса источника и назначения, чтобы я мог также получить

ip источника — ip назначения — общее количество полученных пакетов — общее количество отправленных пакетов

Буду признателен за любую помощь

Ответ №1:

просто смотрю на исходный IP:

 awk '
    NR == 1 {next}
    {
        recv[$1]  = $3
        sent[$1]  = $4
    }
    END {for (ip in recv) printf("%s - %d - %dn", ip, recv[ip], sent[ip]}
' filename
  

для пар источник / назначение просто небольшая модификация:

 awk '
    NR == 1 {next}
    {
        key = $1 " - " $2
        recv[key]  = $3
        sent[key]  = $4
    }
    END {for (key in recv) printf("%s - %d - %dn", key, recv[key], sent[key])}
' filename
  

Ответ №2:

Ruby (1.9 )

 #!/usr/bin/env ruby      
hash_recv=Hash.new(0)
hash_sent=Hash.new(0)
hash_src_dst_recv=Hash.new(0)
hash_src_dst_sent=Hash.new(0)
f=File.open("file")
f.readline
f.each do |line|
    s = line.split
    hash_recv[s[0]]  = s[2].to_i
    hash_sent[s[0]]  =  s[-1].to_i
    hash_src_dst_recv[ s[0,2] ]  =  s[2].to_i
    hash_src_dst_sent[ s[0,2] ]  =  s[-1].to_i
end
f.close
p hash_recv
p hash_sent
p hash_src_dst_recv
p hash_src_dst_sent
  

тестовый запуск:

 $ ruby test.rb
{"192.168.0.1"=>3787, "192.168.168.0.1"=>34}
{"192.168.0.1"=>718, "192.168.168.0.1"=>243}
{["192.168.0.1", "10.10.10.1"]=>3753, ["192.168.0.1", "10.22.22.2"]=>34, ["192.168.168.0.1", "192.168.9.3"]=>34}
{["192.168.0.1", "10.10.10.1"]=>384, ["192.168.0.1", "10.22.22.2"]=>334, ["192.168.168.0.1", "192.168.9.3"]=>243}
  

Комментарии:

1. @MJB, OP также поместил тег в «scripting». Это не обязательно должно быть awk .

Ответ №3:

Я бы сделал (немного отформатированный, но вы могли бы записать его в одной строке):

 sort file.txt | awk ' BEGIN {start = 1;} 
                           { 
                            ip = $1; 
                            if (lastip == ip) { 
                               sum_r  = $3; sum_s  = $4; 
                               }
                            else 
                               { if (!start) print lastip ": " sum_r ", " sum_s
                                 else 
                                    start = 0;
                                 lastip = ip; sum_r = $3; sum_s = $4;
                                }
                            }
                       END { print lastip ": " sum_r ", " sum_s }'
  

Ответ №4:

  awk '{
       if (NR==FNR){ 
         Recieved[$1,$2] =$3;Sent[$1,$2] =$4;
       }else{
           if(Recieved[$1,$2]){
             print $1" " $2" " Recieved[$1,$2]" "Sent[$1,$2];Recieved[$1,$2]=""
           }
       }
      }' InputFile.txt InputFile.txt
  

Входной файл считывается дважды, следовательно, он добавляется два раза в конце.
Первое применение inputfile (которое используется в условии if (NR==FNR)) заключается в построении двух массивов, а второй inputfile (используемый в условии else) предназначен для печати всех комбинаций, а также для установки значения массива пустым, чтобы мы не печатали снова.

Решение Гленна, приведенное ниже, намного лучше, оно считывает файл только один раз