2016-07-11 4 views
0

最初の列に顧客IDを含む複数のカンマ区切りの列を含むファイルがあります。 1つの顧客IDが複数の行に表示されることがありますが、常に同じ実際の顧客を参照します。カンマ区切りファイルで顧客IDに基づく計算を実行する

このID列に基づいてシェルスクリプトで基本的な計算を実行するにはどうすればよいですか?たとえば、特定の顧客IDのマイル数の合計(第5フィールド)を計算します。

102,305,Jin,Kerala,40   
104,308,Paul,US,45    
105,350,Nina,AUS,50   
102,390,Jin,Kerala,10   
104,395,Paul,US,35    
102,399,Jin,Kerala,35 

第5フィールドはマイレージ、第1フィールドは顧客IDです。

+1

を私はSQLiteのように、いくつかのデータベースにそれをインポートし、SQLクエリとして、すべての数学を行うだろう。 – wilx

答えて

0

:あなたを与える

$ awk '{sum[$1] += $2} {for (key in sum) { print key": "sum[key]}}' inputFile 

:シングルパス・ソリューションについては

、あなたのようなものを使用することができます最後の合計と一緒に顧客ID:

#!/usr/bin/awk -f 

BEGIN { FS = "," } 

{ 
    customer_id = $1; 
    mileage = $5; 
    total_mileage[customer_id] += mileage; 
} 

END { 
    for (customer_id in total_mileage) { 
     print customer_id, total_mileage[customer_id]; 
    } 
} 

To r国連(後に実行可能chmod +x script.awkでそれを作る):

$ ./script.awk data.in 
102 85 
104 80 
105 50 

また、「ワンライナー」として:

$ awk -F, '{t[$1]+=$5} END {for (c in t){print c,t[c]}}' data.in 
102 85 
104 80 
105 50 
+0

ありがとうございます。出来た :) – Hariharan

0

あなたは(最初の列を仮定すると、IDである)のようなものを使用したユニークなIDのリストを取得することができます。

awk '{print $1}' inputFile | sort -u 

これは、入力ファイルinputFile内のすべての単一の行の最初のフィールドを出力し、それらをソートし、重複を削除します。

bashループでこのメソッドを使用すると、別のawkコマンドで固有のIDのそれぞれを処理して、何らかのアクションを実行できます。各個別IDのために、それは最初のIDは、そのIDと一致する唯一のプロセスラインにawkを使用して出力し、そのコードに

for id in $(awk '{print $1}' inputFile | sort -u) ; do 
    echo "${id}:" 
    awk -vid=${id} '$1==id {print " "$0)' inputFile 
done 

:次のコードでは、私は、一致する各IDの行を印刷します。実行されるアクションは、インデント付きのフルラインを出力することです。

もちろん、各IDに一致する行で任意の操作を行うことができます。以下に示すように、お客様の要件に一層よく合った例です。

まず、ここで私はテストのために使用される入力ファイルだ - 私たちは、フィールド1は、顧客IDとフィールド2の走行距離であると仮定することができます

$ cat inputFile 
a 1 
b 2 
c 3 
a 4 
b 5 
c 6 
a 7 
b 8 
c 9 
b 10 
c 11 
c 12 

そして、ここで提案した方法のコマンドライントランスクリプト(ノートです

$ for id in $(awk '{print $1}' inputFile | sort -u) ; do 
+ awk -vid=${id} ' 
+  $1==id {print $0; sum += $2 } 
+  END {print "Total: "sum; print } 
+  ' inputFile 
+ done 

a 1 
a 4 
a 7 
Total: 12 

b 2 
b 5 
b 8 
b 10 
Total: 25 

c 3 
c 6 
c 9 
c 11 
c 12 
Total: 41 

キープI:$+がそれぞれ入力プロンプトと継続プロンプトであることを、彼らは、実際のコマンドの一部)ではありません巨大ではないデータセットの場合は、awkスクリプトを使用して、結合配列を使用して合計を格納した後、ENDブロックのすべてのデータを出力することもできます。私自身は、メモリ不足の可能性を最小限に抑えるため、マルチパス・アプローチを自分自身より好む傾向があります。もちろん、ファイルを2回以上処理しているので、間違いなく長い時間がかかります。これは、マイレージを総括し、印刷しますシンプルawkスクリプトです

a: 12 
b: 25 
c: 41 
+0

Downvote:1つのAwkスクリプトですべてを行うことが標準的な解決策になります。 idで配列に集約し、ENDブロックでIDキーをループして印刷します。また、最初のコード断片には誤ったタイプミスがあります。 – tripleee

+0

@ tripleee、typoを修正しました。しかし、過去には、巨大なデータセットを 'awk'に読み込もうとしていたので、私はマルチパスの方が好きです。 downvoteに関しては、それはあなたの権利ですが、私はあなたが "役に立たない"(しかし犯行はない)というやや歪んだ定義を持つかもしれないと信じています。他のアプローチがあるという事実は、私の意見では、このアプローチを悪いものにしていません。しかし、いずれにせよ、私はこれが重複していることに同意し、おそらく閉鎖されるべきです。 – paxdiablo

0

私はデータベースを使用して賢くかもしれないと@wilxに同意するが、このサンプルawkスクリプトがあなたが始める必要があります。

awk -v FS=',' '{miles[$1] += $5} 
    END { for (customerid in miles) { 
     print customerid, miles[customerid]; } }' customers 
関連する問題