web-dev-qa-db-ja.com

awkを使用して、別の列の値に基づいて列の値を合計する

awkを使用して列の特定の数値を合計しようとしています。 「smiths」の列3だけを合計して合計で212にしたいと思います。「smiths」だけでなく、awkを使用して列全体を合計できます。私が持っています:

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

また、PuTTYを使用しています。助けてくれてありがとう.

smiths|Login|2
olivert|Login|10
denniss|Payroll|100
smiths|Time|200
smiths|Logout|10
75
jake
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • -Fフラグはフィールド区切り文字を設定します。シェルの特殊文字なので、一重引用符で囲みます。
  • 次に、$1 ~ /smiths/は、次の{code block}を、最初のフィールドが正規表現/smiths/と一致する行にのみ適用します。
  • 残りはコードと同じです。

ここでは実際には正規表現を使用していないため、特定の値のみを使用しているため、次のように簡単に使用できます。

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

文字列の等価性をチェックします。これは、別の回答で述べたように、正規表現/^smiths$/を使用することと同等です。これには、^アンカーを使用して文字列の先頭(フィールド1の先頭)のみを照合し、$アンカーを使用して文字列の末尾のみを照合します。正規表現にどの程度慣れているかわからない。それらは非常に強力ですが、この場合、文字列の等価性チェックを簡単に使用できます。

95
Wildcard

別のアプローチは、awk連想配列を使用することです。詳細は here です。この行は、必要な出力を生成します。

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
19
Andrey

今のところとても良いです。必要なのは、ブロックの前にセレクターを追加して、合計を追加することだけです。ここで、最初の引数に「smiths」のみが含まれていることを確認します。

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

オプションとしてフィールドセパレータを指定することで、これを少し短くすることができます。 awkでは、コマンドラインで変数を初期化することをお勧めします。

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

私は個人的にはawkセクションをできるだけ単純にして、それなしでできる限りのことをしたいと思っています。 ComingledロジックはUnixパイプラインの能力を活用していないため、密接に関連するユースケースの理解、デバッグ、変更が困難です。

cat filename.txt | Perl -pe 's{.*|}{}g' | awk '{sum+=$1} END {print sum}'
1
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -Fオプションでセパレータを指定します。
  • $NFは「最後の列」用です。
0
forzagreen