基于范围的awk slab计算

时间:2014-06-13 12:59:31

标签: awk

想根据StartRange,EndRange,Category和Flag_value信息计算slab计算。

SampleInput.txt

Field1,Field2,Field3,Field4,Field5,Field6
Desc,Name,Category,Desc2,Flag_Value,Slab_Count
ZZZ,ABC,A,xyz,2,140
ZZZ,CDE,A,xyz,-5,140
ZZZ,FGH,B,xyz,10,48
ZZZ,IJK,B,xyz,-10,48
ZZZ,LMN,C,xyz,115,248
ZZZ,OPQ,A,ijk,-62,250
ZZZ,RST,D,ijk,67,350
ZZZ,UVW,A,ijk,-80,5
ZZZ,XYZ,A,ijk,48,6

Slab.txt

StartRange,EndRange,Category-A,Category-B,Category-C,Category-D,Flag_Value
1,50,350,350,500,500,-125
51,100,450,500,550,600,-150
101,150,600,600,600,650,-150
151,200,700,650,650,650,-200
201,250,800,750,700,700,-250
251,1000,900,850,800,800,-300

计算SampleInput.txt第一行的方法,需要从SampleInput.txt输入Field3(即A),Field5> 0(即2)和Field6(即140) 然后从Slab.txt查找数据,找到平躺范围(即101,150,600,600,600,650,-150),类别(即A类)和打印对应值,即600

SampleInput.txt的第二行,需要从SampleInput.txt输入Field3(即A),Field5< 0(即-5)和Field6(即140)然后从Slab.txt查找数据 找到平躺范围(即101,150,600,600,600,650,-150),类别(即A类)并打印相应的加法类别-A + Flag_Value,即450(600-150)

预期的Output.txt

Desc,Name,Category,Desc2,Flag_Value,Slab_Count,Slab_Amt
ZZZ,ABC,A,xyz,2,140,600
ZZZ,CDE,A,xyz,-5,140,450
ZZZ,FGH,B,xyz,10,48,350
ZZZ,IJK,B,xyz,-10,48,225
ZZZ,LMN,C,xyz,115,248,700
ZZZ,OPQ,A,ijk,-62,250,550
ZZZ,RST,D,ijk,67,350,800
ZZZ,UVW,A,ijk,-80,5,225
ZZZ,XYZ,A,ijk,48,6,350

在谷歌搜索了很多相关的尝试但未找到相同的内容,坚持在复杂的级别找到,寻找你的建议。

2 个答案:

答案 0 :(得分:2)

这是另一种可能性:

awk '
BEGIN { FS = OFS = "," } 
NR == 1 { next } 
FNR == 1 { print $0, "Slab_Amt" }
NR == FNR { 
    range[$1,$2,"A"] = $3
    range[$1,$2,"B"] = $4
    range[$1,$2,"C"] = $5
    range[$1,$2,"D"] = $6
    flag[$1,$2] = $NF
    next
}   
{
    for (key in range) {
        split (key, tmp, SUBSEP);
        if (tmp[3] == $3 && tmp[1] <= $NF && $NF <= tmp[2]) {
            value = ( $5 > 0 ? range[key] : range[key] + flag[tmp[1],tmp[2]] )
            print $0, value
            next
        }
    }
}' Slab.txt SampleInput.txt

输出:

Desc,Name,Category,Desc2,Flag_Value,Slab_Count,Slab_Amt
ZZZ,ABC,A,xyz,2,140,600
ZZZ,CDE,A,xyz,-5,140,450
ZZZ,FGH,B,xyz,10,48,350
ZZZ,IJK,B,xyz,-10,48,225
ZZZ,LMN,C,xyz,115,248,700
ZZZ,OPQ,A,ijk,-62,250,550
ZZZ,RST,D,ijk,67,350,800
ZZZ,UVW,A,ijk,-80,5,225
ZZZ,XYZ,A,ijk,48,6,350

说明:

  • 我们使用,
  • 将输入和输出字段分隔符设置为BEGIN { FS = OFS = "," }
  • 如果它是第一个文件的第一行,我们使用NR == 1 { next }
  • 跳过它
  • 对于第二个文件的第一行,我们使用Slab_Amt
  • 打印添加FNR == 1 { print $0, "Slab_Amt" }标题
  • 我们遍历Slab.txt文件,该文件存储我们的多维数组中每个类别的值,其中包含range数组中的起始范围,结束范围和类别作为键。
  • 我们将标记值存储在键入开始和结束范围的flag数组中。
  • 当我们开始处理SampleInput.txt文件时,我们迭代我们的范围数组并拆分密钥。
  • 我们检查我们的第三个键是否等于样本输入的第3列,最后一列是否在我们的范围之间。如果是,我们通过检查第5列是否大于0来计算该值。如果是,我们只是指定范围的值,否则我们将范围值添加到标记值并打印该行以及我们的值。
  • 使用next我们跳过进一步检查并转到下一行样本输入。

答案 1 :(得分:0)

这是一种可能性。

awk -F, '
BEGIN {
  getline <"Slab.txt"  # skip header
  while ((getline <"Slab.txt") > 0)
    slabs[int($2)] = $0
  # Last index must be greater than top of range
  slabs[999999] = "endmarker"
}
NR == 2 { print $0",Slab_Amt" }
NR > 2 {
  n = int($6)
  for (rangetop in slabs)
    if (n <= int(rangetop))
      break
  if (rangetop == 999999) {
    print "n out of range:",n >"/dev/stderr"
    exit(1)
  }
  split(slabs[rangetop], fields, ",")
  switch ($3) {
  case "A":  val = fields[3]; break
  case "B":  val = fields[4]; break
  case "C":  val = fields[5]; break
  case "D":  val = fields[6]; break
  default:
    print "unknown category:",$3 >"/dev/stderr"
    exit(1)
  }
  if ($5 < 0)
     val += fields[7]
  print $0","val
}
' SampleInput.txt