必要な複数の列を合計する関数を作成する方法

必要な複数の列を合計する関数を作成する方法

複数の列を合計したいシナリオがあります。

ファイルのデータは次のとおりです。

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タグの総コストが必要です。

簡単な命令で一つ作ったのに関数を作ってどうするのか

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

関数は、列名を渡すときにその列の合計を計算するようにパラメータ化する必要があります。

合計列は異なる場合があります。 2つの列の合計のみが必要な場合は、2つの列名を取得してその合計を処理する必要があるのと同じ要件になることがあります。

答え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

関連情報