你能帮我吗?我有一个任务。我输入了一些带有数字的文本。例如:
beta 1
score 9
something 2
beta 4
something 1
我需要计算周围具有相同文本的所有数字。我的输出将是:(以这种方式使用“:”)
beta:5
something:3
score:9
另外,临时文件也可能有问题,我可以在其中保存我的分数。我需要mktemp
在脚本完成后使用来删除它。请帮助我,谢谢。
答案1
我假设输入每行始终包含两个字段。
您可以使用 GNUdatamash
实用程序对数据进行排序,按第一个字段进行分组,并计算每组第二个字段的总和:
datamash -s -W --output-delimiter=: groupby 1 sum 2 <file
此处,对-s
输入进行排序,-W
使实用程序将任何连续的空白字符视为字段分隔符,并将--output-delimiter=:
输出分隔符设置为该:
字符。其余部分告诉datamash
按第一个字段进行分组并计算每组第二个字段的总和。
给定名为 的文件中问题的输入file
,这将产生以下输出:
beta:5
score:9
something:3
您也可以通过许多其他方法来解决这个问题。最简单的计算解决方案是使用awk
:
awk '{ sum[$1] += $2 } END { for (key in sum) printf "%s:%d\n", key, sum[key] }' file
在这里,我们使用关联数组sum
来保存第一个字段中每个字符串的总和。该END
块在输入末尾执行,并将计算出的总和与字符串一起输出。
请注意,此解决方案还假设第一个字段是不包含空格字符的单个单词,如问题所示。
使用 shell 循环,从原始文件中读取排序后的行,每当遇到新的第一个字段时打印并重置第二个字段的总和:
unset -v prev
sort file |
{
while read -r key value; do
if [ "$key" != "${prev-$key}" ]; then
# prev is set and different from $key
printf '%s:%d\n' "$prev" "$sum"
sum=0
fi
prev=$key
sum=$(( sum + value ))
done
if [ "${prev+set}" = set ]; then
printf '%s:%d\n' "$prev" "$sum"
fi
}
答案2
如果您正在处理大文件,请考虑使用sort
和awk
,这样我们就不会在 RAM 中分配巨大的数组来存储键和值。
λ cat input.txt
beta 1
score 9
something 2
beta 4
something 1
sort input.txt |
awk -v OFS=: 'NR==1{ key=$1 }; NR>1&&$1!=key{ print key, sum; sum=0; key=$1 }; {sum+=$2} END{ print key, sum}'
beta:5
score:9
something:3
答案3
#!/bin/bash
declare -i SECOND
while read first second; do
if [ -z $FIRST ] || [ $first = $FIRST ]; then
SECOND+=second
else
echo $FIRST:$SECOND
SECOND=second
fi
FIRST=$first
done < <(sort file)
echo $FIRST:$SECOND
通常我会写一个类似的空白,并在生产中将所有变量放在引号中。
答案4
for k in $(awk '{if(!seen[$1]++)print $1}' file.txt); do awk -v k="$k" 'BEGIN{sum=0}$0 ~ k {sum=sum+$2}END{print k,sum}' file.txt; done
输出
beta 5
score 9
something 3