2017-12-18 27 views
6

にそれらの値を合計:ソート・キーと、私は次のような文字列のリスト(標準入力)を持っているbashの

1 pineapples 
28 apples 
16 oranges 
8 apples 
2 apples 
2 oranges 
56 pineapples 

は、私はのようにそれらをマージし、合計することができたとのネイティブな方法は、(のようなsort & uniq -c)ありますこの:sort |uniq -cよう

38 apples 
18 oranges 
57 pineapples 

行うだけでなく、出現数のために?

答えて

11

は、この方法を試してください。

awk '{a[$2] += $1} END{for (i in a) print a[i], i}' < in.txt 

出力

38 apples 
57 pineapples 
18 oranges 
+3

awkがジョブのための適切なツールであるとき、それは本当に仕事のための正しいツールです。 – zzxyz

+0

awkを愛していますが、よく分かりませんが、ここに収まると確信しました。 –

+0

これはエレガントですが、出力は*ソートされていません*。それが実際の要件であるかどうかという疑問からは明らかではありませんが、ただ知っておくべきことです。補足として、GNU 'awk' *は、' PROCINFO ["sorted_in"] 'によって制御された、定義された(ソートされた)方法でforループ内の配列をたどることができます(この場合、' PROCINFO ["sorted_in" ] = "@val_str_asc")。 – randomir

0

awkはこの仕事に適したツールです。しかし、awkに慣れておらず、bashバージョン> = 4.0を持っている人には、bash associative arraysの代替バージョンがあります。これにより、Fruitsファイルの各行が読み込まれ、2番目の列をキーとして格納されます。 GNU datamash

declare -A Sumarray 
while IFS=" " read num thing 
do 
    if [[ -v Sumarray[$thing] ]] 
    then 
    Sumarray[$thing]=$((${Sumarray[$thing]} + $num)) 
    else 
    Sumarray[$thing]=$num 
    fi 
done < Fruits 

$ for K in "${!Sumarray[@]}"; do echo ${Sumarray[$K]} $K ; done 
38 apples 
57 pineapples 
18 oranges 
+1

awkに精通していない人は、awkを学ぶべきです。シェルは、ファイルやプロセスを操作するためのものです。テキストを操作するためのシェルは、シェルを発明した人テキストを操作するために発明された - awk .. –

4

:入力フィールド区切り文字の

$ <file datamash -Wst' ' -g2 sum 1 
apples 38 
oranges 18 
pineapples 57 

-W使用空白、-t' '出力フィールドデリミタ、-sソート入力用のスペース、カラム2によって-g2基、カラムからsum 1合計値を使用)

ここでは大きな勝者ではありませんが(awk以上)、実際にはもう少し複雑に輝いています統計演算(例えば、グループ中央値、分散、歪度などを計算する)。 (それが重要な場合)問題で与えられるよう

形式を取得するには、我々は datamashは常に出力しているため、手動で出力フィールドの順序を逆にする必要があるグループ化することにより、第1列:ソート

$ <file datamash -Wst' ' -g2 sum 1 | datamash -Wt' ' reverse 
38 apples 
18 oranges 
57 pineapples 
0

要約値とawkを使用して出力:

awk '{ 
    items[$2]+=$1 
} 
END { 
    asorti(items, sorted) 
    for(i in sorted) 
     print items[sorted[i]] " " sorted[i] 
}' input_file 

は使用のみbash

declare -A items=() 

while read -r num item; do 
    ((items[$item] += num)) 
done < input_file 

sorted=() 
while IFS= read -r -d '' item; do 
    sorted+=("$item") 
done < <(printf '%s\0' "${!items[@]}" | sort -z) 

for index in "${sorted[@]}"; do 
    echo "${items[$index]} $index" 
done 
関連する問題