我正在编写一个 shell 脚本,我想将唯一值的结果及其计数一次合并到一个文件中。例如,如果我正在从下面的两个文件中读取数据(第一列中的数字是唯一计数):
第一个循环读取数据
3 Dog
1 Cat
5 Horse
Data Read in Second Loop
1 Dog
3 Cat
1 Horse
2 Goat
我希望将第二个和第一个文件合并,以便将我的“计数文件”覆盖为:
第二次循环完成后的结果文件
4 Dog
4 Cat
6 Horse
2 Goat
我试图完成此任务,因为数据集很大,我宁愿读取和删除文件而不是下载(或者将cat
文件放在一起并uniq -c
在最后找到,因为文件会很长)。有没有办法做到这一点?谢谢你!
答案1
此方法用于awk
对临时文件tallytmp
和名为简单的运行计数进行求和tally
。我将sort
第二个字段上的两个计数文件放在一起 ( -k2
)
它需要一个空白文件tally
开始,所以touch tally
,然后对于每次迭代:
uniq -c file > tallytmp
sort -k2 tally tallytmp \
|awk '{
if($2==prev){
tot+=$1
}else{
print tot,prev;
tot=$1;pc=$1;prev=$2
}
}END{
print tot,prev
}' > tallyresult
cp tallyresult tally
(继续,将awk
脚本放在一行中。)
从逻辑上讲,我应该能够将sort|awk
管道直接重定向到tally
,但sort
仍在使用它,所以它会破坏它;因此tallyresult
在将其复制到我们的结果文件之前,需要第二个临时文件tally
。
所提供的两次迭代的输出实际上是:
[blank line]
4 Cat
4 Dog
2 Goat
6 Horse
顺序是根据字段 #2 的顺序混合的,但它工作正常。我能够使用它运行一些迭代。
答案2
有人刚刚对我之前的答案投了赞成票,所以我当然必须发明一个新的解决方案!这个更好一点,有两个原因:
- 它是纯粹的
bash
,使用哈希表而不是依赖awk
- 你不会看到垃圾空白行
- 可以添加任意数量的文件
tally
(三个原因) - 文件
tally
可能开始为空(四个原因) - 它不需要临时文件(“我没想到”等)
将以下内容另存为tally.sh
#!/bin/bash
# define the associative array tally_table
declare -A tally_table
while read line ; do
k=($line)
[ -n "${k[1]}" ] && (( tot[${k[1]}] += ${k[0]} ))
done <<HERE
$(cat tally $@)
HERE
for i in "${!tally[@]}"; do
echo "${tally[$i]} $i"
done > tally
cat tally
尝试删除tally
并创建一个新的报告文件,命名file
为以下几行:
1 Horse
3 Monkey
然后将其输入:
$ ./tally.sh file
3 Monkey
1 Horse
现在创建另一个报告,名称newfile
为几行:
5 Horse
2 Pig
并喂它:
$ ./tally.sh newfile
3 Monkey
6 Horse
2 Pig
该Horse
条目已正确递增。当然,就像以前一样,顺序不一致。 (我不知道你会如何排序狗猫马山羊订购,或属于Monkey
其中的位置。)