基于slab的awk计数和总和:

时间:2014-06-27 13:24:47

标签: unix awk

如果第一个文件第4个字段落在一个范围内,则想从第一个文件(GunZip * .gz,即Input.csv.gz)中提取所有行。 第二个文件(Slab.csv)第一个字段(开始范围)和第二个字段(结束范围)然后填充Slab明智的行数和第一个文件的第4和第5个字段的总和。

Input.csv.gz(GunZip)

Desc,Date,Zone,Duration,Calls
AB,01-06-2014,XYZ,450,3
AB,01-06-2014,XYZ,642,3
AB,01-06-2014,XYZ,0,0
AB,01-06-2014,XYZ,205,3
AB,01-06-2014,XYZ,98,1
AB,01-06-2014,XYZ,455,1
AB,01-06-2014,XYZ,120,1
AB,01-06-2014,XYZ,0,0
AB,01-06-2014,XYZ,193,1
AB,01-06-2014,XYZ,0,0
AB,01-06-2014,XYZ,161,2

Slab.csv

StartRange,EndRange
0,0
1,10
11,100
101,200
201,300
301,400
401,500
501,10000

预期产出:

StartRange,EndRange,Count,Sum-4,Sum-5
0,0,3,0,0
1,10,NotFound,NotFound,NotFound
11,100,1,98,1
101,200,3,474,4
201,300,1,205,3
301,400,NotFound,NotFound,NotFound
401,500,2,905,4
501,10000,1,642,3

我使用以下两个命令来获得上述输出,期望" NotFound" case。

awk -F, 'NR==FNR{s[NR]=$1;e[NR]=$2;c[NR]=$0;n++;next} {for(i=1;i<=n;i++) if($4>=s[i]&&$4<=e[i]) {print $0,","c[i];break}}' Slab.csv <(gzip -dc Input.csv.gz) >Op_step1.csv
cat Op_step1.csv | awk -F, '{key=$6","$7;++a[key];b[key]=b[key]+$4;c[key]=c[key]+$5} END{for(i in a)print i","a[i]","b[i]","c[i]}' >Op_step2.csv

Op_step2.csv

101,200,3,474,4
501,10000,1,642,3
0,0,3,0,0
401,500,2,905,4
11,100,1,98,1
201,300,1,205,3

任何建议使其成为预期输出的一个班轮命令,不要有perl,python访问。

2 个答案:

答案 0 :(得分:3)

这是使用perl的另一个选项,它可以创建多维数组和哈希。

perl -F, -lane'
BEGIN {
    $x = pop; 
    ## Create array of arrays from start and end ranges
    ## $range = ( [0,0] , [1,10] ... )
    (undef, @range)= map { chomp; [split /,/] } <>; 
    @ARGV = $x;
}
## Skip the first line
next if $. ==1; 
## Create hash of hash
## $line = '[0,0]' => { "count" => counts , "sum4" => sum_of_col4 , "sum5" => sum_of_col5 }
for (@range) { 
  if ($F[3] >= $_->[0] && $F[3] <= $_->[1]) { 
    $line{"@$_"}{"count"}++; 
    $line{"@$_"}{"sum4"} +=$F[3]; 
    $line{"@$_"}{"sum5"} +=$F[4];
  } 
} 
}{ 
  print "StartRange,EndRange,Count,Sum-4,Sum-5"; 
  print join ",", @$_, 
  $line{"@$_"}{"count"} //"NotFound",  
  $line{"@$_"}{"sum4"}  //"NotFound", 
  $line{"@$_"}{"sum5"}  //"NotFound" 
    for @range
' slab input
StartRange,EndRange,Count,Sum-4,Sum-5
0,0,3,0,0
1,10,NotFound,NotFound,NotFound
11,100,1,98,1
101,200,3,474,4
201,300,1,205,3
301,400,NotFound,NotFound,NotFound
401,500,2,905,4
501,10000,1,642,3

答案 1 :(得分:2)

以下是使用awksort的一种方式:

awk '
BEGIN { 
    FS = OFS = SUBSEP = ",";
    print "StartRange,EndRange,Count,Sum-4,Sum-5" 
} 
FNR == 1 { next }
NR == FNR {
    ranges[$1,$2]++;
    next
}
{
    for (range in ranges) {
        split(range, tmp, SUBSEP); 
        if ($4 >= tmp[1] && $4 <= tmp[2]) {
            count[range]++;
            sum4[range]+=$4;
            sum5[range]+=$5; 
            next
        }
    }
}
END {
    for(range in ranges) 
        print range, (count[range]?count[range]:"NotFound"), (sum4[range]?sum4[range]:"NotFound"), (sum5[range]?sum5[range]:"NotFound") | "sort -t, -nk1,2"
}' slab input
StartRange,EndRange,Count,Sum-4,Sum-5
0,0,3,NotFound,NotFound
1,10,NotFound,NotFound,NotFound
11,100,1,98,1
101,200,3,474,4
201,300,1,205,3
301,400,NotFound,NotFound,NotFound
401,500,2,905,4
501,10000,1,642,3
  • 将输入,输出字段分隔符和SUBSEP设置为,。打印标题行。
  • 如果是第一行则跳过它。
  • 将整个slab.txt加载到名为ranges的数组中。
  • 对于ranges数组中的每个范围,拆分字段以获取开始和结束范围。如果第4列在范围内,则递增计数数组并将值适当地添加到sum4sum5数组。
  • END块中,遍历范围并打印它们。
  • 将输出传递给sort以按顺序获取输出。