複数の列を合計したいシナリオがあります。
ファイルのデータは次のとおりです。
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