解决Bash中grep报错并实现首两列重复行的平均值计算
问题描述
数据集
15.0 -100.0 409.27 5.7103 0.0106 0.0062 652.04 15.0 -99.5 409.14 5.6868 0.0109 0.0065 652.02 15.0 -99.0 409.23 5.4866 0.0108 0.0063 651.47 15.0 -98.5 409.19 5.4588 0.0107 0.0063 651.34 15.0 -98.5 409.17 5.3488 0.0105 0.0062 651.30 15.0 -98.0 409.16 5.2951 0.0104 0.0061 651.24 15.0 -97.5 409.17 5.2647 0.0104 0.0061 651.22 15.0 -97.0 409.27 5.0288 0.0098 0.0056 650.60
需求
对比每行前两列,若两行前两列值相同,则计算其余5列的平均值并合并为一行;若不同则保留原行。
编写的Bash代码
sort -k 1 -n -k 2 -n file1 > temp awk '{print $1, $2}' temp | uniq > file2 while read line do n=`grep -c "$line" temp` #echo $n grep -E "$line" temp > temp1 awk -v n=$n '{sum+=$3} END {print sum/n}' temp1 > val1; awk -v n=$n '{sum+=$4} END {print sum/n}' temp1 > val2; awk -v n=$n '{sum+=$5} END {print sum/n}' temp1 > val3; awk -v n=$n '{sum+=$6} END {print sum/n}' temp1 > val4; awk -v n=$n '{sum+=$7} END {print sum/n}' temp1 > val5; echo $line $val1 $val2 $val3 $val4 $val5 >> Averages.dat; done < file2
报错信息
grep: invalid option -- '.'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
问题解决
1. 修复grep报错
报错原因是$line包含以-开头的内容(比如-100.0),grep会将其识别为命令选项而非匹配字符串。可以通过两种方式解决:
- 使用
--分隔选项与匹配模式,明确告知grep后续内容是匹配字符串:n=$(grep -c -- "$line" temp) grep -F -- "$line" temp > temp1 - 加上
-F参数启用固定字符串匹配,避免正则解析的同时,配合--彻底避免选项混淆(此处无需正则匹配,固定匹配更高效)。
2. 修正变量赋值错误
原代码将awk结果输出到文件,echo $line $val1实际输出的是文件名而非文件内的平均值。需改用命令替换直接将结果赋值给变量:
val1=$(awk '{sum+=$3} END {print sum/NR}' temp1) val2=$(awk '{sum+=$4} END {print sum/NR}' temp1) val3=$(awk '{sum+=$5} END {print sum/NR}' temp1) val4=$(awk '{sum+=$6} END {print sum/NR}' temp1) val5=$(awk '{sum+=$7} END {print sum/NR}' temp1)
这里用NR(当前处理行数)替代传入的n,代码更简洁可靠。
3. 高效的纯awk替代方案
原bash循环多次调用grep和awk,效率极低。可以用awk一步完成排序、分组求平均的全部操作,无需临时文件:
awk ' { key = $1 FS $2 sum3[key] += $3 sum4[key] += $4 sum5[key] += $5 sum6[key] += $6 sum7[key] += $7 count[key]++ } END { PROCINFO["sorted_in"] = "@ind_num_asc" # 按数字顺序排序结果 for (k in count) { printf "%s %.4f %.4f %.4f %.4f %.4f\n", k, sum3[k]/count[k], sum4[k]/count[k], sum5[k]/count[k], sum6[k]/count[k], sum7[k]/count[k] } } ' file1 > Averages.dat
该脚本的作用:
- 以前两列为分组键,累加各列总和与计数
- 最后遍历所有分组,计算并输出平均值,同时按数字顺序排序
- 用
printf控制小数精度,避免输出冗余位数
内容的提问来源于stack exchange,提问作者Monika
相关产品推荐
相关产品推荐

