これは何?
たまに使いたくなる言語個人的 NO 1 AWK のあんちょこ。
普段は cut として使っているが、ちょっと込み入ったことがしたくなったときに頭をチューニングするための覚え書きです。
執筆環境
--csv オプションを使いたいので gawk。
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.3 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
$ gawk -V
GNU Awk 5.3.60, API 4.0, PMA Avon 8-g1
Copyright (C) 1989, 1991-2024 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
サンプルデータ
CSV サンプルデータ でググったら上の方に出てきた。
文字コードが Shift_JIS だった。
nkf -w -Lu -O ./c01.csv ./全国人口.csv
注意すること
-
サンプルデータの文字コードを確認する
- 文字コードは UTF-8(LF) が良い
- 変換コマンド
nkf -w -Lu -O ./INPUT ./OUTPUT
-
キーワードは大文字
- 大文字小文字を区別する
- BEGIN を Begin などと書くと動かない
-
暗黙の動作
PATTERN PATTERN {print} PATTERN {print $0}は同じ動作。
-
パターンとアクションは同じ行に置く。別々の行に置くには、バックスラッシュによる行継続を使わなければならない
よって改行に注意することPATTERN {ACTION}は想定通りに動作しない。
-
AWK の配列は全て連想配列。
Array[1]は数字を添字にしているように見えるが、実際はArray["1"]
使用例
- スッとグラフ化する
データを作るとそれが正しいのかチェックするわけですが、数字を睨んでいてもよくわからない。
グラフにするとわかってくる気がするので、とりあえずグラフ化がしたいわけです。こうすれば awk からパイプをつないでいきなりグラフを書けるようになる。
alias PLOT='gnuplot -p -e "
set key off;
set decimalsign locale;
set format y \"%'\''.0f\";
plot \"<cat\" using 1:2 with lines
"'
こんなふうに使う。
# 福井は数少ない観測開始の 1920 年以外がもっとも人口が少なかった地域
# 後は戦後すぐあたりか、島根
cat ./全国人口.csv | gawk --csv '$2 ~ /福井/{print $5,$7}' | PLOT
- CSV の数字を計算する
グラフ化できるようになると次はデータを作りたいですね。
awk は grep と cut を合体させた以上のことができるコマンドです。例として 1920 - 2015 年の人口データから各県の人口がもっとも少なかった年を求めるプログラムを書きます。
# 全国の最小人口とその年を求める
$2 ~ /(都|道|府|県)$/ {
pop = $7 + 0
year = $5 + 0
pref = $2
# 欠落値は数値化すると 0 になる
if (pop == 0){
next
}
if (!(pref in min_popu) || pop < min_popu[pref]) {
min_popu[pref] = pop
min_year[pref] = year
code[pref] = $1 + 0
}
}
END {
# print される順番は保証されないが、
# どのみち sort などのコマンドと組み合わせて使うので気にしない
for (pref in min_popu){
print code[pref],pref,min_year[pref],min_popu[pref]
}
}
これをパイプでつなげることで、先程の福井がどのくらい珍しいのかを調べてみましょう。
$ cat ./全国人口.csv | gawk --csv -f ./全国の最小人口とその年.awk | gawk '{print $3}' | sort | uniq -c
43 1920
2 1925
1 1945
1 2015
- 列名で CSV を扱う
計算しているとフィールド番号と内容の関係を何度も確認することになって面倒だと感じるでしょう。
CSV ヘッダーをキーにしたフィールド参照でフィールド番号を意識しない CSV 処理ができます。
# CSV ヘッダーをキーにしたフィールド参照:男女比を表示する
#
# CSV: ヘッダー
# "都道府県コード","都道府県名","元号","和暦(年)","西暦(年)","注","人口(総数)","人口(男)","人口(女)"
NR == 1 {
for (i = 1; i<=NF; i++) {
header[$i] = i
}
next
}
# 人口統計がない年はスキップする
# ヘッダーもフッダーもスキップする
$(header["人口(総数)"]) !~ /-/ && NF > 1 {
printf "%s %d %d %f\n",
$(header["都道府県名"]),
$(header["西暦(年)"]),
$(header["人口(総数)"]),
$(header["人口(男)"]) / $(header["人口(女)"])
}
# 全国 1920 55963053 1.004489
# 北海道 1920 2359183 1.116123
# 青森県 1920 756454 1.016345
# ...
