简体   繁体   English

Bash脚本Awk if语句

[英]Bash Script Awk if statements

Given a input file with record format... (ID #, First name, Last name, Score1, Score2, Score3, Score(N).. Important note: There will be numerous records in file (not just 1 row). 给定一个具有记录格式的输入文件...(ID号,名字,姓氏,Score1,Score2,Score3,Score(N)。。 重要说明:文件中将有许多记录(不仅仅是1行)。

I would like to be able to provide output format such as.. (ID #, Average Score, Grade letter corresponding to average score) 我希望能够提供输出格式,例如:(ID号,平均分数,与平均分数相对应的成绩字母)

Example of input: 输入示例:

900123123 Joe Brown 100 90 80
900900900 Tyler Black 80 95 75
900231231 Stephen Williams 70 75 80
900111111 Andrew Smith 85 75 90

Example of output: 输出示例:

900123123 90 A
900900900 83.3 B
900231231 75 C
900111111 83.3 B

My issue is the if-statements to determine what grade letter to assign. 我的问题是if语句,以确定要分配的年级字母。 Here is my current code: 这是我当前的代码:

#!/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

This will result in the output: 这将导致输出:

900123123 Joe Brown 90  A
900323323 Tyler Black 83.3333  A
900231231 Stephen Williams 75  A
900232232 Andrew Smith 83.3333  A
   0  A

Why is the first if statement being hit every time even when average is less than 90? 为什么即使平均值小于90也会每次都击中第一个if语句? We know this because it is used inside of the print statement and prints out A with any number. 我们知道这一点是因为它在print语句内部使用,并打印出任意数量的A。 Also, I have no idea why 0 A is output and what the cause of this may be. 另外,我也不知道为什么输出0 A ,这可能是什么原因。

Your first condition was: 您的第一个条件是:

if (average -ge 90)

As @thatotherguy poined out, -ge is a shell construct and the equivalent in awk is >= . 正如@thatotherguy指出的那样, -ge是一个shell构造,而awk中的等效项是>= To awk your statement reads as: awk的陈述如下:

if ( (average - ge) 90 )

which is to say: subtract the numeric value of the unassigned variable named ge (ie zero) from the variable average and then concatenate the string 90 to the result so if average was 70 , for example then it'd read as: 这就是说:从变量average减去未分配的变量ge的数值(即零),然后将字符串90连接到结果,因此,例如,如果average为70 ,则其读为:

if ( (70 - 0) 90 )

which after the subtraction is: 减去后为:

if ( 70 90 )

which after the concatenation is: 串联后的是:

if ( 7090 )

which is a true condition and so you're script will always execute the subsequent line of code since no matter what the result of the subtraction is you're always going to concanetate it with 90 and end up with a non-zero and non-null result. 这是一个真实的条件,因此您的脚本将始终执行后续的代码行,因为无论减法的结果是什么,您始终会将其代入90并最终得到一个非零且非零的空结果。

The 0 A at the end of your output is almost certainly because you have a blank line at the end of your input file. 输出末尾的0 A几乎可以肯定,因为输入文件末尾有一个空行。 You can guard against that by testing NF before entering the action block. 您可以通过在进入操作块之前测试NF来防范此情况。

Here's a suggestion on how to write your script: 这是有关如何编写脚本的建议:

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

There's no point testing for && average < 90 when you're in the else part of a condition that tested for average >= 90 . 当您处于测试average >= 90的条件的else部分时,不会对&& average < 90进行点测试。

There are two problems: 有两个问题:

  1. -ge/-le is for bash, while awk is a separate programming language that uses >= and <= -ge/-le用于bash,而awk是使用>=<=的独立编程语言
  2. You can't shorten if statements by leaving out an operand the second time it's used ( && -le 90 ). 您不能通过在第二次使用操作数时省略它来缩短if语句( && -le 90 )。

If you rewrite 如果重写

if(average -ge 80 && -le 90)

into 进入

if (average >= 80 && average <= 90)

it'll work. 会的。

This rafactored awk script should work for you: 这个经过分解的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

OUTPUT: 输出:

900123123 Joe Brown 90.00 A
900900900 Tyler Black 83.33 B
900231231 Stephen Williams 75.00 C
900111111 Andrew Smith 83.33 B

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM