我是Bash的新手,所以请在这里忍受我。
我有一个由另一个软件(我无法控制)转储的文本文件列出每个用户访问某些资源的次数,如下所示:
吉姆109 鲍勃94 约翰92 肖恩91 马克85 理查德84 吉姆79 鲍勃70 约翰67 肖恩62 马克59 理查德58 吉姆57 鲍勃55 约翰49 肖恩48 马克46 。 。 。
我的目标是获得这样的输出。
吉姆[吉姆总计] 鲍勃[鲍勃总数] 约翰[约翰的总数]
等等。
每次我在软件中运行查询时,名称都会改变,所以静态search每个名称,然后通过wc进行pipe道操作并没有帮助。
这听起来像是awk
的工作:)将程序的输出传递给下面的awk
脚本:
your_program | awk '{a[$1]+=$2}END{for(name in a)print name " " a[name]}'
输出:
Sean 201 Bob 219 Jim 245 Mark 190 Richard 142 John 208
awk
脚本本身可以用这种格式更好地解释:
# executed on each line { # 'a' is an array. It will be initialized # as an empty array by awk on it's first usage # '$1' contains the first column - the name # '$2' contains the second column - the amount # # on every line the total score of 'name' # will be incremented by 'amount' a[$1]+=$2 } # executed at the end of input END{ # print every name and its score for(name in a)print name " " a[name] }
请注意,要获得按分数排序的输出,可以添加另一个管道来sort -r -k2
。 -r -k2
按相反的顺序排列第二列:
your_program | awk '{a[$1]+=$2}END{for(n in a)print n" "a[n]}' | sort -r -k2
输出:
Jim 245 Bob 219 John 208 Sean 201 Mark 190 Richard 142
纯粹的Bash:
declare -A result # an associative array while read name value; do ((result[$name]+=value)) done < "$infile" for name in ${!result[*]}; do printf "%-10s%10d\n" $name ${result[$name]} done
如果第一个“完成”没有从输入文件重定向,则该脚本可以与管道一起使用:
your_program | ./script.sh
并对输出进行排序
your_program | ./script.sh | sort
输出:
Bob 219 Richard 142 Jim 245 Mark 190 John 208 Sean 201
GNU数据 datamash
:
datamash -W -s -g1 sum 2 < input.txt
输出:
Bob 219 Jim 245 John 208 Mark 190 Richard 142 Sean 201