给定一个带记录格式的输入文件...... (ID#,名字,姓氏,Score1,Score2,Score3,Score(N).. 重要提示:文件中会有大量记录(不只是1行)。
我希望能够提供输出格式,例如.. (ID#,平均分数,与平均分相对应的成绩字母)
输入示例:
900123123 Joe Brown 100 90 80
900900900 Tyler Black 80 95 75
900231231 Stephen Williams 70 75 80
900111111 Andrew Smith 85 75 90
输出示例:
900123123 90 A
900900900 83.3 B
900231231 75 C
900111111 83.3 B
我的问题是确定要分配的成绩字母的if语句。这是我目前的代码:
#!/bin/bash
awk '
BEGIN {FS=OFS=" "}
{
sum=0; average=0
for(i=3;i<=NF;i++)
{sum+=$i;}
average = (sum/(NF-3))
if (average -ge 90)
print $1, $2, $3, average, " A";
else if(average -ge 80 && -le 90)
print $1, $2, $3, average, " B";
else if(average -ge 70 && -le 80)
print $1, $2, $3, average, " C";
else if(average -ge 60 && -le 70)
print $1, $2, $3, average, " D";
else
print $1, $2, $3, average, "F";
}' grades.txt
这将导致输出:
900123123 Joe Brown 90 A
900323323 Tyler Black 83.3333 A
900231231 Stephen Williams 75 A
900232232 Andrew Smith 83.3333 A
0 A
为什么即使平均值小于90,每次都会发出第一个if语句?我们知道这一点,因为它在print语句中使用并打印出任何数字的A.
另外,我不知道为什么输出0 A
以及原因可能是什么。
答案 0 :(得分:4)
你的第一个条件是:
if (average -ge 90)
正如@thatotherguy一样,-ge
是一个shell构造,而awk中的等价物是>=
。要把你的陈述写成:
if ( (average - ge) 90 )
也就是说:从变量ge
中减去名为average
的未赋值变量(即零)的数值,然后将字符串90
连接到结果,如果是平均值是70
,例如,它读作:
if ( (70 - 0) 90 )
减法后的是:
if ( 70 90 )
串联后的是:
if ( 7090 )
这是一个真实的条件,因此你的脚本将始终执行后续的代码行,因为无论减法的结果是什么,你总是要用90
来加速它。并以非零和非空结果结束。
输出结尾处的0 A
几乎可以肯定是因为输入文件末尾有一个空行。您可以在进入操作块之前测试NF
来防范这种情况。
以下是关于如何编写脚本的建议:
awk 'NF {
sum=0
for(i=3;i<=NF;i++)
sum+=$i
average = sum/(NF-3)
if (average >= 90) grade = "A"
else if (average >= 80) grade = "B"
else if (average >= 70) grade = "C"
else if (average >= 60) grade = "D"
else grade = "F"
print $1, $2, $3, average, grade
}' grades.txt
&& average < 90
当您在else
测试条件的average >= 90
部分时,对{{1}}进行无法测试。
答案 1 :(得分:3)
有两个问题:
-ge/-le
适用于bash,而awk
是一种使用>=
和<=
的单独编程语言&& -le 90
),则不能缩短if语句。如果你改写
if(average -ge 80 && -le 90)
到
if (average >= 80 && average <= 90)
它会工作。
答案 2 :(得分:2)
这个糟糕的awk脚本应该适合你:
#!/bin/bash
awk '{
sum=0;
for(i=3;i<=NF;i++)
{sum+=$i;}
average = (sum/(NF-3));
avgstr = sprintf("%s%s%s%s%s%s%.2f", $1, OFS, $2, OFS, $3, OFS, average);
if (average >= 90)
print avgstr, "A";
else if(average >= 80 && average <= 90)
print avgstr, "B";
else if(average >= 70 && average <= 80)
print avgstr, "C";
else if(average >= 60 && average <= 70)
print avgstr, "D";
else
print avgstr, "F";
}' grades.txt
900123123 Joe Brown 90.00 A
900900900 Tyler Black 83.33 B
900231231 Stephen Williams 75.00 C
900111111 Andrew Smith 83.33 B