使用awk根据另一列的值求和一列的值


63

我正在尝试使用将某列中的某些数字相加awk。我只想对“史密斯”的第3列求和,从而得出总数为212。我可以对整个列进行求和,awk而不仅仅是“史密斯”。我有:

awk 'BEGIN {FS = "|"} ; {sum+=$3} END {print sum}' filename.txt

我也在用腻子。感谢您的任何帮助。

smiths|Login|2
olivert|Login|10
denniss|Payroll|100
smiths|Time|200
smiths|Logout|10

Answers:


81
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • -F标志设置字段分隔符;我将其用单引号引起来,因为它是一个特殊的外壳字符。
  • 然后$1 ~ /smiths/将以下{code block}仅应用于第一个字段与regex匹配的行/smiths/
  • 其余与您的代码相同。

请注意,由于您实际上并没有真正使用正则表达式,而只是使用特定值,因此可以轻松使用:

awk -F '|' '$1 == "smiths" {sum += $3} END {print sum}' inputfilename

哪个检查字符串是否相等。/^smiths$/正如在另一个答案中提到的,这等效于使用regex ,它包括^仅与字符串的开头(字段1的开头)$匹配的锚和仅与字符串的末尾匹配的锚。不知道您对正则表达式有多熟悉。它们非常强大,但是在这种情况下,您可以轻松地使用字符串相等性检查。


3
顺便说一下,我最喜欢的awk参考是grymoire.com/Unix/Awk.html。非常有用的页面。
2015年

1
谢谢@Wildcard!根据您的建议,我能够在大的zip档案中巧妙地聚合特定文件的未压缩大小:) unzip -lv /appl/tmp/data.lar | grep documentlibrary | awk '{sum += $1} END {print sum/1024/1024}'
Pawel

15

另一种方法是使用awk关联数组,更多信息请参见。这行产生所需的输出:

awk -F '|' '{a[$1] += $3} END{print a["smiths"]}' filename.txt

副作用是,该数组存储所有其他值:

awk -F '|' '{a[$1] += $3} END{for (i in a) print i, a[i]}' filename.txt

输出:

smiths 212
denniss 100
olivert 10

这是正确的答案
PoVa

5

到目前为止很好。您需要做的就是在块前添加一个选择器以添加总和。在这里,我们检查第一个参数是否仅包含“ smiths”:

awk 'BEGIN {FS = "|"} ; $1 ~ /^smiths$/ {sum+=$3} END {print sum}'

您可以通过指定字段分隔符作为一个选项来缩短此时间。在awk一般的初始化命令行变量是一个好主意:

awk -F'|' '$1 ~ /^smiths$/ {sum+=$3} END {print sum}'

0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F 指定分隔符的选项。
  • $NF 用于“最后一栏”。

1
cat并且grep是不必要在这里。
安德烈

为什么不需要grep @Andrey?OP只想添加“史密斯”行。您需要修改awk语句,对不对?
EL

1
@EL是的,/smiths/{...}如果grep调用不存在,则应将awk语句修改为。这是一个微不足道的修改,但是它提供了很多好处:减少正在运行的进程的数量,简化错误控制,并使代码更清晰。
Andrey

0

我个人更希望使该awk部分尽可能简单,并且在没有它的情况下尽可能多地执行。混合逻辑没有利用Unix管道的功能,因此对于紧密相关的用例更难以理解,调试或修改。

cat filename.txt | perl -pe 's{.*|}{}g' | awk '{sum+=$1} END {print sum}'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.