【问题标题】:Process multiple file using awk使用 awk 处理多个文件
【发布时间】:2015-11-29 01:02:04
【问题描述】:

我必须使用 awk 处理大量 txt 文件(每个文件有 1600 万行)。例如,我必须阅读十个文件:

文件#1:

en sample_1 200
en.n sample_2 10
en sample_3 10

文件 #2:

en sample_1 10
en sample_3 67

文件#3:

en sample_1 1
en.n sample_2 10
en sample_4 20

...

我想要这样的输出:

源标题 f1 f2 f3 sum(f1,f2,f3)

en sample_1 200 10 1 211
en.n sample_2 10 0 10 20
en sample_3 10 67 0 77
en sample_4 0 0 20 20 

这是我的第一个版本的代码:

#! /bin/bash
clear
#var declaration
BASEPATH=<path_to_file>
YEAR="2014"
RES_FOLDER="processed"
FINAL_RES="2014_06_01"
#results folder creation
mkdir $RES_FOLDER
#processing
awk 'NF>0{a[$1" "$2]=a[$1" "$2]" "$3}END{for(i in a){print i a[i]}}' $BASEPATH/$YEAR/* > $RES_FOLDER/$FINAL_RES

这是我的输出:

en sample_1 200 10 1
en.n sample_2 10 10
en sample_3 10 67
en sample_4 20

我有点困惑如何将零列放在没有发现的地方以及如何获得所有值的总和。 我知道我必须使用这个:

{tot[$1" "$2]+=$3} END{for (key in tot) print key, tot[key]}

希望有人能提供帮助。谢谢。

********已编辑********

我正在尝试以不同的方式实现我的结果。 我创建了一个这样的 bash 脚本,它使用我的所有键生成一个排序文件,它非常大,大约有 6200 万条记录,我将这个文件分成几块,然后将每一块传递给我的 awk 脚本。

重击:

#! /bin/bash
clear
FILENAME=<result>
BASEPATH=<base_path>
mkdir processed/slice
cat $BASEPATH/dataset/* | cut -d' ' -f1,2 > $BASEPATH/processed/aggr
sort -u -k2 $BASEPATH/processed/aggr > $BASEPATH/processed/sorted
split -d -l 1000000 processed/sorted processed/slice/slice-
echo $(date "+START PROCESSING DATE: %d/%m/%y - TIME: %H:%M:%S")
for filename in processed/slice/*; do
  awk -v filename="$filename" -f algorithm.awk dataset/* >> processed/$FILENAME
done
echo $(date "+END PROCESSING DATE: %d/%m/%y - TIME: %H:%M:%S")
rm $BASEPATH/processed/aggr
rm $BASEPATH/processed/sorted
rm -rf $BASEPATH/processed/slice

AWK:

BEGIN{
while(getline < filename){
 key=$1" "$2;
 sources[key];
 for(i=1;i<11;i++){
   keys[key"-"i] = "0";
 }
}
close(filename);
}
{
if(FNR==1){
 ARGIND++;
}
key=$1" "$2;
keys[key"-"ARGIND] = $3
}END{
for (s in sources) {
 sum = 0
 printf "%s", s
 for (j=1;j<11;j++) {
   printf "%s%s", OFS, keys[s"-"j]
   sum += keys[s"-"j]
 }
print " "sum
}
}

我使用 awk 预分配我的最终数组,并读取 dataset/* 文件夹我填充它的内容。 我发现我的瓶颈来自通过 awk 输入迭代数据集文件夹(10 个文件,每个文件有 16.000.000 行)。 一切都在处理一小部分数据,但是对于真实数据,RAM (30GB) 很拥挤。有没有人有任何建议或意见?谢谢。

【问题讨论】:

  • 文件排序了吗?
  • 是的,它们已排序

标签: linux bash unix awk bigdata


【解决方案1】:
$ cat tst.awk
{
    key = $1" "$2
    keys[key]
    val[key,ARGIND] = $3
}
END {
    for (key in keys) {
        sum = 0
        printf "%s", key
        for (fileNr=1;fileNr<=ARGIND;fileNr++) {
            printf "%s%s", OFS, val[key,fileNr]+0
            sum += val[key,fileNr]
        }
        print sum
    }
}

$ awk -f tst.awk file1 file2 file3
en sample_4 0 0 2020
en.n sample_2 10 0 1020
en sample_1 200 10 1211
en sample_3 10 67 077

上面使用 GNU awk 作为 ARGIND,其他 awk 只需在开头添加一行 FNR==1{ARGIND++}。如有必要,将输出通过管道传输到 sort

【讨论】:

  • 我正在尝试在一组非常大的数据(10 个文件,每个文件有 16.000.000 行 - 500Mb)上处理此算法。处理需要很长时间,RAM 很拥挤,所以将开始交换(4 GB RAM)。你有什么建议吗?我应该改变编程语言吗?谢谢。
  • 更改编程语言无济于事,更改您的平台以增加内存/CPU 或更改您的算法以以某种方式分割文件并分块处理它们是您唯一的选择。例如,您可以从所有文件中选择所有 $1 值,然后为每个键值运行一次上述脚本。这将花费更长的时间但使用更少的内存,因此如果您当前的性能问题是由于内存不足而导致的,实际上可能没问题。您可以选择 10 或 1,000 或其他对您的数据有意义的值,而不是一次一个键。
【解决方案2】:
awk -vn="<source> <title>" 'function w(m,p){while(split(a[m],t)!=b+2)sub(p," 0&",a[m])}FNR<2{f=FILENAME;o=o?o" <"f">":"<"f">";q=q?q","f:f;++b}{a[$1" "$2]=a[$1" "$2]?a[$1" "$2]" "$NF:$0;w($1" "$2," [^ ]*$");c[$1" "$2]+=$NF}END{print n,o,"sum<("q")>";for(i in a){w(i,"$");print a[i],c[i]|"sort -k2"}}' *
<source> <title> <f1> <f2> <f3> sum<(f1,f2,f3)>
en sample_1 200 10 1 211
en.n sample_2 10 0 10 20
en sample_3 10 67 0 77
en sample_4 0 0 20 20

【讨论】:

    【解决方案3】:

    由于您的文件非常大,您可能希望使用join -- 它可能会更快和/或使用更少的内存。但是,它需要对文件进行排序并具有单个连接字段。

    join -a1 -a2 -e0 -o0,1.2,2.2     <(sed $'s/ /\034/' file1 | sort) \
                                     <(sed $'s/ /\034/' file2 | sort) | 
    join -a1 -a2 -e0 -o0,1.2,1.3,2.2 - \
                                     <(sed $'s/ /\034/' file3 | sort) | 
    awk '{sub(/\034/," "); print $0, $3+$4+$5}' 
    

    根据要求提供说明

    【讨论】:

      猜你喜欢
      • 2021-09-18
      • 1970-01-01
      • 1970-01-01
      • 2013-02-05
      • 1970-01-01
      • 1970-01-01
      • 2014-09-04
      • 2016-09-05
      • 1970-01-01
      相关资源
      最近更新 更多