我有点Bash新手,所以请在这里忍受我。
我有一个由另一个软件(我无法控制)转储的文本文件,列出每个用户访问某些资源的次数,如下所示:
Jim 109 Bob 94 John 92 Sean 91 Mark 85 Richard 84 Jim 79 Bob 70 John 67 Sean 62 Mark 59 Richard 58 Jim 57 Bob 55 John 49 Sean 48 Mark 46 . . .
我的目标是获得这样的输出。
Jim [Total for Jim] Bob [Total for Bob] John [Total for John]
等等。
每次在软件中运行查询时名称都会更改,因此对每个名称进行静态搜索,然后通过wc进行管道传输无效。
答案 0 :(得分:6)
这听起来像是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
答案 1 :(得分:4)
Pure 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
如果第一个'done'没有从输入文件重定向 这个脚本可以用于管道:
your_program | ./script.sh
并对输出进行排序
your_program | ./script.sh | sort
输出:
Bob 219
Richard 142
Jim 245
Mark 190
John 208
Sean 201
答案 2 :(得分:1)
GNU datamash
:
datamash -W -s -g1 sum 2 < input.txt
输出:
Bob 219
Jim 245
John 208
Mark 190
Richard 142
Sean 201