在bash中对键进行排序和求和

时间:2017-12-18 20:11:33

标签: bash awk

我有一个字符串列表(stdin),如下一个:

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

是否有本地方式(例如sort& uniq -c),我可以将其合并并将它们相加:

38 apples
18 oranges
57 pineapples

sort |uniq -c类似,但不仅仅是出现次数?

4 个答案:

答案 0 :(得分:13)

试试这个:

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

输出

38 apples
57 pineapples
18 oranges

答案 1 :(得分:4)

使用GNU datamash

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

-W使用空格表示输入字段分隔符,-t' '使用空格表示输出字段分隔符,-s排序输入,-g2组第2列,{{1}来自每个组中第1列的值。)

这里不是一个大赢家(超过sum 1),但它确实对更复杂的统计操作有所启发(例如计算组中位数,方差,偏度等)。

要获得有问题的格式(如果这很重要),我们需要手动反转输出字段的顺序,因为awk始终首先输出分组列:

datamash

答案 2 :(得分:0)

Awk是这项工作的合适工具。但是,对于那些不熟悉awk且bash版本> gt = 4.0的人来说,这是一个带有bash associative arrays的替代版本。这将读取文件Fruits的每一行,并使用第二列作为键存储数字。

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

答案 3 :(得分: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