2016-03-14 84 views
1

我有一个脚本来比较一堆CSV文件中的一些列。 它工作正常,但有一些东西正在扰乱我。使用AWK将FILENAME打印到CSV

下面是代码:

FILES=./* 
for f in $FILES 

do 
    cat -v $f | sed "s/\^A/,/g" > op_tmp.csv 
    awk -F, -vOFS=, 'NR == 1{next} $9=="T"{t[$8]+=$7;n[$8]} $9=="A"{a[$8]+=$7;n[$8]} $9=="C"{c[$8]+=$7;n[$8]} $9=="R"{r[$8]+=$7;n[$8]} $9=="P"{p[$8]+=$7;n[$8]} END{ for (i in n){print i "|" "A" "|" a[i]; print i "|" "C" "|" c[i]; print i "|" "R" "|" r[i]; print i "|" "P" "|" p[i]; print i "|" "T" "|" t[i] "|" (t[i]==a[i]+c[i]+r[i]+p[i] ? "ERROR" : "MATCHED")} }' op_tmp.csv >> output.csv 
    rm op_tmp.csv 
done 

只是解释: 我上目录中的所有文件,然后我使用CAT来代替除数^一种用于管道|。 然后我使用awk onliner比较我需要的列并将结果输出到output.csv。

但现在我想在每个循环之前打印文件名。 我试图用sed的猫和awk在同一直线上,并打印$文件名,但它不工作:

cat -v $f | sed "s/\^A/,/g" | awk -F, -vOFS=, 'NR == 1{next} $9=="T"{t[$8]+=$7;n[$8]} $9=="A"{a[$8]+=$7;n[$8]} $9=="C"{c[$8]+=$7;n[$8]} $9=="R"{r[$8]+=$7;n[$8]} $9=="P"{p[$8]+=$7;n[$8]} END{ for (i in n){print i "|" "A" "|" a[i]; print i "|" "C" "|" c[i]; print i "|" "R" "|" r[i]; print i "|" "P" "|" p[i]; print i "|" "T" "|" t[i] "|" (t[i]==a[i]+c[i]+r[i]+p[i] ? "ERROR" : "MATCHED")} }' > output.csv 

谁能帮助?

回答

1

您可以更好地重写整个剧本,但假设它你想要做什么awk的电话之前,现在只需加

echo $f >> output.csv

如果你想在每一个AWK输出线添加文件名,你必须把它作为参数传递,即

awk ... -v fname="$f" '{...; print fname... etc 
1

重写:

for f in ./*; do 
    awk -F '\x01' -v OFS="|" ' 
     BEGIN { 
      letter[1]="A"; letter[2]="C"; letter[3]="R"; letter[4]="P"; letter[5]="T" 
      letters["A"] = letters["C"] = letters["R"] = letters["P"] = letters["T"] = 1 
     } 
     NR == 1 {next} 
     $9 in letters { 
      count[$9,$8] += $7 
      seen[$8] 
     } 
     END { 
      print FILENAME 
      for (i in seen) { 
       sum = 0 
       for (j=1; j<=4; j++) { 
        print i, letter[j], count[letter[j],i] 
        sum += count[letter[j],i] 
       } 
       print i, "T", count["T",i], (count["T",i] == sum ? "ERROR" : "MATCHED") 
      } 
     } 
    ' "$f" 
done > output.csv 

注:

  • 只要你的文件名有一个空格,你的迭代文件的方法就会中断
  • 尽量减少重复,尽量使用0
  • 换行是免费的,用它们来提高可读性
  • 提高你的变量名in,等等 - 在这里“信”和“信”可以使用改善举办一些意味着那些符号。
  • awk有一个FILENAME变量(这里的实际回答你的问题
  • AWK理解\x01是一个按Ctrl-A - 我认为在你输入的字段分隔符文件
  • 定义输出域分隔符,你会真正使用

如果你有GNU AWK(版本???)你可以使用ENDFILE块,并与外壳for环干脆做掉:

gawk -F '\x01' -v OFS="|" ' 
    BEGIN {...} 
    FNR == 1 {next} 
    $9 in letters {...} 
    ENDFILE { 
     print FILENAME 
     for ... 
     # clean up the counters for the next file 
     delete count 
     delete seen 
    } 
' ./* > output.csv 
+0

即使没有gawk,你也可以和其他一些调整一起,将END块放在一个函数中,并在'FNR == 1'和'END'条件下调用它,你不需要shell循环。 'ENDFILE'出现在gawk 4.0 btw中,请参阅http://www.gnu.org/software/gawk/manual/gawk.html#Feature-History。 –

+0

重写工作,最终我会更新到类似的东西,但现在我只是调整使用变量$ fname并在每个循环之前打印。还删除了临时文件和猫。万分感谢。 –