来自文件的AWK引用列基于列的标题

时间:2016-12-13 12:33:04

标签: shell awk

我在cmd.awk中有以下代码:

 BEGIN {FS=","}
 {
    if(FNR==1) print $0",Header";
    else if (FNR>1)
            {
                    if($79==0 && $80==0 && $81==0) print $0",0";
                    else if ($80==0 && $81!=0) print $0","($79-$81)/$81;
                    else if ($81==0 && $80!=0) print $0","($79-$80)/$80;
                    else if ($81==0 && $80==0 && $79!=0) print $0",10";
                    else if ($81!=0 && $80!=0) print $0","(($79-$80)/$80)+(($80-$81)/$81);
            }
}

当我执行以下命令时:

awk -f cmd.awk input.txt

它执行所需的操作(在AWK脚本中指定)并提供所需的结果。

但是在这个脚本中,输入txt文件的所有列都是基于column_index访问的,即$ 79,$ 80,$ 81等。

我的要求是我需要使用这个脚本作为一个函数,它需要79美元,80美元,81美元和Header(在脚本中给出)作为参数,执行操作并将结果存储在新添加的列中,列名为Header和将新内容存储到输出文件中。但我只允许以列标题的形式指定参数而不是列索引,即我的函数调用必须是这样的:

cmd(column_header1, column_header2, column_header3,new_header)

并且cmd()的函数定义必须执行上面awk脚本中提到的操作。

有没有办法做到这一点?请记住,我对awk很新。提前谢谢。

我的输入文件包含150列和超过50M行。该文件的样本如下:

RN,DATE,ID,PRE_M1,PRE_M2,GALV,GALG,PRE_M5.........................TOTAL
0624873840,2016/04/28,201610,1618,0,0,0,Active,.................12234
0747269250,2016/02/02,201610,227,93,0,0,Daat,....................99988

输入文件包含numeric,character类型的列。在上面的AWK脚本中访问的列都是数字类型。

所需输出文件的示例如下:

RN,DATE,ID,PRE_M1,PRE_M2,GALV,GALG,PRE_M5.........................TOTAL,Header
0624873840,2016/04/28,201610,1618,0,0,0,Active,.................12234,10
0747269250,2016/02/02,201610,227,93,0,0,Daat,....................99988,0

请注意,新列将附加到名称为" Header"的文件中。此列包含输入文件的每一行的AWK脚本的结果。

2 个答案:

答案 0 :(得分:0)

# --- for your sample test ----------
column_1=1;column_2=2;column_3=3;new_header="Header"

---通用代码------

awk -v Col1=${column_1} -v Col2=${column_2} -v Col3=${column_3} -v NewH="${new_header}" -F ',' '
  BEGIN { OFS = FS }
  FNR == 1 {
     $(NF + 1) = NewH
     print $0
     next
     }
  {
   if      ( ! $Col1 && ! $Col2 && ! $Col3) NewV = 0
   else if ( ! $Col2 && $Col3 )             NewV = ($Col1-$Col3)/$Col3
   else if ( ! $Col3 && $Col2 )             NewV = ($Col1-$Col2)/$Col2
   else if ( ! $Col3 && ! $Col2 && $Col1 )  NewV = 10
   else if ( $Col3 && $Col2)                NewV = (($Col1-$Col2)/$Col2)+(($Col2-$Col3)/$Col3)
   print $0
   }' YourFile
  • 通过awk的-v参数将值传递给变量(整数是asis,字符串是引用的(参见NewH)
  • var == 0与if中的! var相同(您可以保留您的版本以提高可读性)
  • 行末不需要;(这是在线人员的指令分隔符)

你可以直接捕获awk中的参数,但与使用-v调用awk相比有点重要

答案 1 :(得分:0)

我认为你可以简化它,没有输入文件所以飞行盲目......

假设感兴趣的列是连续的并且字段都是数字,只需提供起始地址

$ awk -F, -v s=79 'BEGIN {OFS=FS}
                   NR==1 {$(NF+1)="Header"}
                   NR >1 {v1=$s; v2=$(s+1); v3=$(s+2)
                          if(!v2 && !v3) $(NF+1) = v1?10:0
                          else $(NF+1) = v3?(v1-v3)/v3:0 + v2?(v1-v2)/v2:0}1' file

参数列名称可以写为

$ cols="c1,c2,c3"; header="Header"
$ awk -F, -v cols="$cols" -v hdr="$header" '
           BEGIN {OFS=FS}
           NR==1 {n=split(cols,cn); 
                  for(i=1;i<=NF;i++) 
                    for(j=1;j<=n;j++) 
                      if($i==cn[j]) c[++k]=i; 
                  $(NF+1)=hdr}
           NR >1 {v1=$c[1]; v2=$c[2]; v3=$c[3]
                  if(!v2 && !v3) $(NF+1) = v1?10:0
                  else $(NF+1) = v3?(v1-v3)/v3:0 + v2?(v1-v2)/v2:0}1' file

id,c1,c2,c3,Header
1,0,0,0,0
2,0,0,1,-1
3,0,1,0,-1
4,0,1,1,-1
5,1,0,0,10
6,1,0,1,0
7,1,1,0,0
8,1,1,1,0

用于给定的输入文件

id,c1,c2,c3
1,0,0,0
2,0,0,1
3,0,1,0
4,0,1,1
5,1,0,0
6,1,0,1
7,1,1,0
8,1,1,1

<强>解释

n=split(cols,cn)使用相同的FS分隔符将字符串“cols”拆分为数组“cn”。元素的数量将被返回并分配给“n”。

1{print}

的简写