awk 在不同列中添加相应的行

awk 在不同列中添加相应的行

我有一个名为 Presidents.txt 的文件。里面的内容如下...

First  Last  Age  Years
Geogre W     57   8.0
John   A     61   4.0
Thomas J     57   8.0
James  M     57   8.0
Andrew J     61   8.0

我需要的是一个程序,可以添加每位总统的年龄和年数。例如,乔治 W 为 57+8.0,约翰 A 为 61+4.0,依此类推。将每位总统的数字相加后,程序将输出数字最大的总统的名字。例如,此处的输出应为“Andrew J at 69”。到目前为止,我可以一次为每位总统执行此操作,但我希望使用 awk 循环完成此操作。到目前为止我一直使用的命令是

awk 'NR==2 {print $3+$4}' presidents.txt

这会将数字 61 和 4.0 相加,得到输出 65,我认为这是一个开始。我确信我需要使用循环和数组,但不知道从哪里开始,因为我对 Unix 或一般编码没有太多经验。任何帮助表示赞赏。

答案1

假设当 $3+$4 存在重复结果时,您只希望打印输入中最后一次出现的此类结果:

$ cat tst.awk
NR>1 {
    curYear = $3 + $4
    if ( curYear >= maxYear ) {
        maxName = $1 OFS $2
        maxYear = curYear
    }
}
END {
    print maxName, "at", maxYear
}

$ awk -f tst.awk file
Andrew J at 69

例如,给定这个修改后的输入文件,其中 2 个人 (Andrew JSheila E) 现在的 $3+$4 总价值均为 69:

$ cat file
First  Last  Age  Years
Geogre W     57   8.0
John   A     61   4.0
Thomas J     57   8.0
James  M     57   8.0
Andrew J     61   8.0
Sheila E     65   4.0

通过上面的脚本,我们得到最后一个输出:

$ awk -f tst.awk file
Sheila E at 69

而也许你想要第一个:

$ cat tst.awk
NR>1 {
    curYear = $3 + $4
    if ( curYear > maxYear ) {
        maxName = $1 OFS $2
        maxYear = curYear
    }
}
END {
    print maxName, "at", maxYear
}

$ awk -f tst.awk file
Andrew J at 69

或全部:

$ cat tst.awk
NR>1 {
    curYear = $3 + $4
    if ( curYear >= maxYear ) {
        if ( curYear > maxYear ) {
            numNames = 0
        }
        maxNames[++numNames] = $1 OFS $2
        maxYear = curYear
    }
}
END {
    for ( nameNr=1; nameNr<=numNames; nameNr++ ) {
        print maxNames[nameNr], "at", maxYear
    }
}

$ awk -f tst.awk file
Andrew J at 69
Sheila E at 69

答案2

结合awksort

awk '{print $1,$2,"at",$3+$4}' file | sort -k4nr | head -1
Andrew J at 69

我们创建一个中间文件,将年龄和年份的总和作为最后一个字段,然后sort使用k最后一个4字段、n数字和r反向,最后只打印第一行head


这是一项改进,用于涵盖多个具有最大年份的行的情况。我们将它们全部打印出来:

awk '{print $1,$2,"at",$3+$4}' file | sort -k4nr | uniq -f3 --group | sed '/^$/q'

uniq正在对重复的行进行分组(忽略第一个3 f字段,这意味着仅测试最后一个数字),用空行分隔各组,并且仅在第一个空行处sed打印第一组。q

答案3

您甚至不需要任何循环或数组来完成这项工作。尝试:

awk '
            { name= $1 OFS $2 OFS "at" OFS }
NR>1        { age=$3+$4 }
age>ageMax  { ageMax=age; data=name; next }
age==ageMax { data= data ageMax ORS name }
END{ print data ageMax }' infile
  • 记录名字和姓氏部分以{ name= $1 OFS $2 OFS "at" OFS }供将来处理。

  • 跳过标题行并将“年龄”添加到“年份”中NR>1{ age=$3+$4 }

  • 如果“age”值大于“ageMax”,则用“age”值更新“ageMax”的值,并用“name”更新“data” age>ageMax { ageMax=age; data=name; next };该next语句告诉 awk 跳过处理当前行的其余代码,awk 将读取下一行进行处理。

  • 如果我们发现相等的最大 AgeMax 值,则通过将 附加到“数据”值来保留所有这些值age==ageMax { data= data ageMax ORS name }。如果您不需要全部,只需删除这部分代码,然后它将返回具有最高ageMax的第一条记录,或者替换age>ageMaxage>=ageMax返回具有最高ageMax的最后一条记录。

  • 在 处END{ print data ageMax },我们打印结果。

相关内容