Bash Script Awk if语句

时间:2014-05-03 17:02:43

标签: bash awk

给定一个带记录格式的输入文件...... (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以及原因可能是什么。

3 个答案:

答案 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)

有两个问题:

  1. -ge/-le适用于bash,而awk是一种使用>=<=的单独编程语言
  2. 如果使用第二次操作数(&& -le 90),则不能缩短if语句。
  3. 如果你改写

    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