[英]Process multiple file using awk
我必須使用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腳本。
BASH:
#! /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)擁擠不堪。 有沒有人有任何建議或意見? 謝謝。
$ 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,其他awks只是在開頭添加一行FNR==1{ARGIND++}
。 如有必要,將輸出通過管道sort
。
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
由於您的文件非常大,您可能希望使用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}'
根據要求提供說明
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.