如何创建一个函数来求和所需的多列

如何创建一个函数来求和所需的多列

我有一个场景,我想对多列求和

文件中的数据是:

ID|NAME|SAL|COST|PER|TAG

1|A|10|10|20|10|

1|B|10|15|20|10|

1|C|10|17|25|80|

1|D|115|110|20|100|

1|E|10|10|10|10|

我想要 COLUMN - SAL | 的总和成本| PER |标签

我用简单的命令做了一个,但如何通过创建函数来做到这一点

awk '{FS="|"}{s+=$3}END{print s}' file.txt

该函数应该参数化,以便当我传递列名称时它应该计算该列的总和

总和列可能有所不同。它们可能是这样的要求,例如只需要两列总和,那么它应该采用两列名称并处理该总和

答案1

使用awk(并丢失输入字符串中的空格)

myv='SAL|COST|PER|TAG'
awk -v ar="$myv" '
  BEGIN{FS="|"; getline; for (i=1;i<=NF;i++) {if ($i ~ ar) head[i]=0;title[i]=$i}}
  NF>1{for (h in head) head[h]+=$h}
  END{for (h in head) print title[h]":\t"head[h]}
' file

这假设正则表达式匹配是唯一的。如果没有那么...

myv='SAL|COST|PER|TAG'
awk -v ar="$myv" '
  BEGIN{FS="|"; getline; for (i=1;i<=NF;i++) head[$i]=i; split(ar,titles,"|")}
  NF>1{for (i=1; i<=NF; i++) val[i]+=$i}
  END{for (t in titles) print titles[t]":\t"val[head[titles[t]]]}
' file

输出

SAL:    155
COST:   162
PER:    95
TAG:    210

答案2

使用足够新的版本磨坊主

$ mlr --csvlite --allow-ragged-csv-input --fs '|' stats1 -a sum -f SAL file.txt
SAL_sum
155

(仅需要最新版本,因为您的输入是衣衫褴褛即有一个尾随空列,标题中没有相应的名称)。您可以通过将多个列的名称作为逗号分隔列表传递给选项,轻松对 Miller 中的多个列求和-f

... stats1 -a sum -f SAL,COST,PER,TAG ...

类似地与GNU 数据混合

$ datamash -Ht '|' sum SAL,COST,PER,TAG < file.txt
sum(SAL)|sum(COST)|sum(PER)|sum(TAG)
155|162|95|210

答案3

从中汲取灵感https://stackoverflow.com/a/32616101:

$ col=SAL
$ colnum=$(awk -v RS='|' '/'$col'/{ print NR; exit}' testfile)
$ awk '{FS="|"}{s+='$colnum'}END{print s}' testfile 
18

这里的技巧是引用:变量位于单引号之外。

这很容易封装到脚本中sumcols.sh

#!/bin/bash
FILE="$1"
COLUMNS="${@:2}"
for col in $COLUMNS; do
  colnum=$(awk -v RS='|' '/'$col'/{ print NR; exit}' $FILE)
  awk '{FS="|"}{s+='$colnum'}END{print "'$col' ", s}' $FILE
done | column -t

使用要处理的文件作为第一个位置参数来调用它,并跟随要处理的列。例如:

$ ./sumcols.sh testfile SAL COST
SAL   18
COST  24

相关内容