使用 awk 从一个大文件中从第 "A" 行总结到第 "B" 行

Sum up from line "A" to line "B" from a big file using 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 文件中的输入(百万行样本)。 我想根据日期总结持续时间。 我担心的是我想总结前 1000000 行 我使用的 awk 程序是:

test.awk

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

我运行我的脚本

$awk -f test.awk 'file'

我的输入没有考虑我的条件 NR>1 && NR<=1000000

有什么建议吗?请!

您正在寻找这个:

BEGIN { FS = "|" } 
1 < NR && NR <= 1000000 { 
    sub(/ .*/, "", ) 
    key = sprintf("%10s",)
    duration[key] +=  
} 
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

结尾的原因

您没有 post 任何预期的输出,并且您的持续时间字段始终为 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

它没有丢弃你的 header 行,而是使用它来创建一个数组 f[] 将字段名称映射到它们在每一行中的顺序,这样就不必 hard-code持续时间是字段 4(或其他),您只需将其引用为 $(f["duration"]).

任何时候你的输入文件有 header 行,不要丢弃它 - 使用它这样你的脚本就不会与输入文件中的字段顺序耦合。