我需要做的是编写一个名为 avgs 的 shell 程序,该程序将从文件中读取包含数据的行,其中标题行可以位于数据中的任何行。
我必须对最后两列的每一列进行总计和计数,并且不得在总计和计数中包含第一行的数据。
这是包含数据的文件:
92876035 SMITZ S 15 26
95908659 CHIANG R 10 29
SID LNAME I T1/20 T2/30
92735481 BRUCE. R 16 28
93276645 YU C 17 27
91234987 MYRTH R 15 16
shell 程序将向标准输出写入以下行:“平均值为 17 和 24”
这是我尝试过的,但它不起作用
count_ppl=0
total=0
while read ?? ?!
do
total=$((sum+b))
count_ppl=$((count_ppl+1))
done < filename
avg=$(echo "scale=2;$total/$count_ppl" | bc)
echo "The averages are = $avg"
这 ”??”和 ”?!”在“阅读时”旁边有吗,因为我不知道该放什么。
我想这可能会计算一列的一个平均值,但是我如何从列中获取数据并计算两个平均值。
(顺便说一句,这是 bash)。
答案1
不确定“并且不得将第一行的数据包含在总计和计数中”是什么意思。您的意思是必须排除行“92876035 SMITZ S 15 26”,或者只是不“求和”“SID LNAME I T1/20 T2/30”?
和??
需要?!
替换为您需要的变量名称。最后提到的变量名称将保留输入的其余部分。您需要最后两列,因此在您的情况下有 5 列,语句while read
可以是:
while read col1 col2 col3 col4 col5
接下来您需要检查该行是否是标题行。在本例中,我将测试第一列中的单词 SID:
if [ "$col1" != 'SID' ]
从这里我们可以开始计算:
totallines=$((totallines+1))
sumcol4=$((sumcol4+col4))
sumcol5=$((sumcol5+col5))
最后你可以使用以下方法计算平均值
avgcol4=$(echo "scale=2; $sumcol4/$totallines"|bc)
avgcol5=$(echo "scale=2; $sumcol5/$totallines"|bc)
要结束它,您可以使用以下脚本:
#!/bin/bash
while read col1 col2 col3 col4 col5
do
if [ "$col1" != 'SID' ]
then
totallines=$((totallines+1))
sumcol4=$((sumcol4+col4))
sumcol5=$((sumcol5+col5))
fi
done < /path/to/inputfile
avgcol4=$(echo "scale=2; $sumcol4/$totallines"|bc)
avgcol5=$(echo "scale=2; $sumcol5/$totallines"|bc)
printf "The averages are %s and %s" $avgcol4 $avgcol5
另一种方法是使用awk
:
awk '{ if ( $1 != "SID" ) { COL4+=$4; COL5+=$5; } } END { LINES=NR-1; printf "The averages are %.2f and %.2f\n", COL4/LINES, COL5/LINES }' < /path/to/inputfile
上面的命令过滤标题行,否则对第 4 列和第 5 列求和,处理输入文件后,它将把 LINES 变量设置为记录数减 1(标题行)并打印输出行。
bash
和版本awk
都会输出:
The averages are 14.60 and 25.20
答案2
#!/usr/bin/awk -f
NR == 1 { next }
/^[^0-9]/ { next }
{
s1 += $(NF - 1)
s2 += $NF
++n;
}
END {
printf("The averages are %.2f and %.2f\n", s1/n, s2/n)
}
测试:
$ chmod +x avgs
$ ./avgs file
The averages are 14.50 and 25.00
这用于awk
跳过第一行数据(按照问题中的要求)以及包含非数字作为第一个字符的任何行。
对于所有其他行,它将最后两个字段的数字添加到 twe sums1
和s2
,并且还递增计数器n
。
最后,打印结果,保留两位小数。
作为 shell 中的“一行”:
$ awk 'NR==1||/^[^0-9]/{next} {s1+=$(NF-1);s2+=$NF;++n} END {printf("The averages are %.2f and %.2f\n", s1/n, s2/n)}' file
The averages are 14.50 and 25.00
有关的: