2015-11-29 34 views
4

我必須使用awk處理大量的txt文件(每個文件有1600萬行)。我得閱讀例如十個文件:使用awk處理多個文件

文件#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總和(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]} 

希望有人會幫助。謝謝。

******** ******** EDITED

我想實現我的結果不同的一種方式。 我創建了一個像這樣的bash腳本,它生成一個帶有我所有鍵的排序文件,它非常龐大,大約有62百萬條記錄,我將這個文件分割成幾部分,然後將每個部分傳遞給我的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輸入迭代dataset文件夾(每個文件有16000.000行的10個文件)。 一切正在處理一小部分數據,但實際數據,RAM(30GB)擁塞。有沒有人有任何建議或建議?謝謝。

+1

的文件排序? – amdixon

+0

是的,他們排序 –

回答

1
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 
4
$ 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

+1

謝謝,這適合我的需求! –

+0

我試圖在一個非常大的一組數據上處理這個算法(10個文件,每個包含16000.000行 - 500Mb)。處理時間非常長,RAM擁塞,SO將開始交換(4 GB RAM)。你有什麼建議嗎?我應該改變編程語言嗎?謝謝。 –

+0

改變編程語言不會有幫助,改變你的平臺來增加內存/ CPU或者改變你的算法以便以某種方式分割文件並以塊來處理它們是你唯一的選擇。例如,您可以從所有文件中選擇所有$ 1值,然後爲每個鍵值運行一次上述腳本。這將花費更長的時間,但使用更少的內存,所以如果你目前的性能問題是由於內存不足,可能實際上是好的。您一次只能選擇一個密鑰,而不是一個密鑰,您可以選擇10或1,000或其他適合您數據的值。 –

0

因爲你的文件都相當大,您可能需要使用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}' 

應要求提供說明