これは、エキサイトホールディングス Advent Calendar 2025 の6日目の記事です。
本題
こんな感じのtsvファイルがあるとします。(内容はサンプルで仮のものです)
このtsvの中から
- サービスコードが
sv1 - 項目名に
工事を含むが、同軸工事は含まない
行を探したい場合、どうするのが簡単でしょうか?
さらに、該当行のユーザーIDを出したいとする。
sample1.tsv
サービスコード ユーザーID 項目名
sv1 101 基本料
sv1 101 工事費
sv1 101 同軸工事費
sv1 102 基本料
sv1 102 工事費
sv1 201 基本料
sv1 201 工事費
sv2 301 基本料
sv2 401 基本料
sv2 401 工事費
sv2 401 同軸工事費
sv2 402 基本料
sv2 402 工事費
awk便利
grepやcutの組み合わせでごり押す事もできるのですが、改めてawkを使うとさくっと調べる場合には便利だったので、使い方を書きます。
grepやcutでごり押す時の課題点
- grepの普通の正規表現では、「否定後読み」の正規表現が書けない
-
-Pオプションをつけると書けるらしいが、GNU grepのみ - オプションに複雑な正規表現書くの、シェルのエスケープがむずかしくない?
-
- cutのデリミタ指定の
-dオプションだと"\t"の形式でタブが指定できない(デリミタは1文字のみのため)-
-d " "のように直接指定はできるが、ターミナルやブラウザコピペ時にスペースに展開されがち - ターミナル上でタブ文字入力するのむずい (Ctrl+v -> tab をする必要ある)
-
awkで書いたときの良いところ!
対象行の抽出
awk -F "\t" '$1 == "sv1" && (/工事/ && ! /同軸工事/)' sample1.tsv
# awkで patternとactionのaction部分を省略した時は
# {print $0}
# で行をそのまま表示するのと同等です。
sv1 101 工事費
sv1 102 工事費
sv1 201 工事費
- 否定後読み等の複雑な正規表現を使わなくても、単純な正規表現の組み合わせで条件が欠ける!
-
-Fフィールドセパレータのオプションに"\t"形式で指定できる!
ユーザーIDを出す
awk -F "\t" '$1 == "sv1" && (/工事/ && ! /同軸工事/) {print $2}' sample1.tsv
101
102
201
まとめ
tsvをさらっと調査する時に、やっぱりawkって便利だなぁと思いました。
ただ、これ以上複雑な集計等をしたくなった場合はやはりpython(pandas)やperl等のもう少し高級な言語を使った方が良いと思うので、使い所の複雑度としては
grep/cut/sed/sort/uniq等の組み合わせ < awk < python等
くらいの順番で考慮できると良いなと思いました。
参考