使用awk从大文件中的“A”行到“B”行汇总

时间:2015-01-09 18:25:56

标签: awk

aNumber|bNumber|startDate|timeZone|duration|currencyType|cost|
22677512549|778|2014-07-02 10:16:35.000|NULL|NULL|localCurrency|0.00|
22675557361|76457227|2014-07-02 10:16:38.000|NULL|NULL|localCurrency|10.00|
22677521277|778|2014-07-02 10:16:42.000|NULL|NULL|localCurrency|0.00|
22676099496|77250331|2014-07-02 10:16:42.000|NULL|NULL|localCurrency|1.00|
22667222160|22667262389|2014-07-02 10:16:43.000|NULL|NULL|localCurrency|10.00|
22665799922|70110055|2014-07-02 10:16:45.000|NULL|NULL|localCurrency|20.00|
22676239633|433|2014-07-02 10:16:48.000|NULL|NULL|localCurrency|0.00|
22677277255|76919167|2014-07-02 10:16:51.000|NULL|NULL|localCurrency|1.00|

这是我在csv文件中的输入(百万行的样本)。 我想根据日期总结持续时间。 我担心的是我想先总结100万行 我正在使用的awk程序是:

test.awk

BEGIN { FS = "|" } 
NR>1 && NR<=1000000 
FNR == 1{ next } 
{ 
sub(/ .*/,"",$3) 
key=sprintf("%10s",$3)
duration[key] += $5 } END {
printf "%-10s %16s,"dAccused","Duration"
for (i in duration) { 
    printf "%-4s %16.2f i,duration[i]  
}}

我运行我的脚本

$awk -f test.awk 'file'

我的输入并没有考虑我的条件NR&gt; 1&amp;&amp; NR&LT; = 1000000

有什么建议吗?请!

2 个答案:

答案 0 :(得分:3)

您正在寻找:

BEGIN { FS = "|" } 
1 < NR && NR <= 1000000 { 
    sub(/ .*/, "", $3) 
    key = sprintf("%10s",$3)
    duration[key] += $5 
} 
END {
    printf "%-10s %16s\n", "dAccused", "Duration"
    for (i in duration) { 
        printf "%-4s %16.2f i,duration[i]  
    }
}

通过适当的缩进,很多错误都会变得很明显。

您看到1,000,000行的原因是:

NR>1 && NR<=1000000

这是一个没有动作块的条件。默认操作是在条件为真时打印当前记录。这就是为什么你看到很多awk单行以数字1

结尾的原因

答案 1 :(得分:1)

您没有发布任何预期的输出,并且您的持续时间字段始终为NULL,因此仍然不清楚您真正想要的输出,但这可能是正确的方法:

$ cat tst.awk
BEGIN { FS = "|" }
NR==1 { for (i=1;i<NF;i++) f[$i] = i; next }
{
    sub(/ .*/,"",$(f["startDate"]))
    sum[$(f["startDate"])] += $(f["duration"])
}
NR==1000000 { exit }
END { for (date in sum) print date, sum[date] }

$ awk -f tst.awk file
2014-07-02 0

它不是丢弃标题行,而是使用它来创建一个数组f[],它将字段名称映射到每行中的顺序,因此不必硬编码该字段的持续时间是字段4(或其他)您只需将其引用为$(f["duration"])

如果您的输入文件有标题行,请不要丢弃它 - 请使用它,这样您的脚本就不会与输入文件中的字段顺序相关联。