🍣

awkコマンドでパターン検索、テキスト処理をする①

2021/01/07に公開

はじめに

くーばねてすをやっつけるためにLinuxさんと仲良くさせていただいているが、Linuxさんには超大量のテキストがあって、検索するだけではなくたくさんテキスト編集処理もする。
今回はテキストを便利に編集できるように非対話型エディタのawkコマンドを勉強しようと思う。
sedコマンドよりさらに強いやつらしい。

概要

■awkコマンドとは
■printとフィールド(列)検索
■パターンの指定

をまとめた!

awkコマンドとは

awkコマンドはsedコマンドのようにワンライナーで編集を指定し編集結果を表示させる。
「sedコマンドよりさらに高機能なテキスト処理に特化したプログラミング言語である。
本格的なテキスト編集ではRubyやPhythonのようなスクリプト言語が多く使われるがawkもまだまだ多くの場面で使われている。」
らしい('_')難しそう。
awkコマンドの書式

awkコマンドの書式
$ awk 'パターン{アクション}' ファイル

そしてawkコマンドのスクリプトは以下のようになる

awkコマンドのスクリプト
 'パターン {アクション}'

まってパターンってだれ('_')
■パターンとは
アクションを実行するかどうかの条件のこと。
awkでは処理中に読み込んでいく1行の入力テキストを「レコード」という。
パターンは省略することが可能でその場合はすべてのレコード(行)にアクションが実行される。

■printとフィールド(列)指定

awkコマンドで最もよく使われるのが特定のフィールドを抽出して表示する列選択だ。
あるディレクトリのの中をls -lで出力してその結果を編集して、ファイルサイズとファイル名だけを出力してみる。ファイルサイズは5列目、ファイル名は9列目になる。
その行を指定して表示するためのスクリプトは

$ '{print $指定行}'

となる。
ディレクトリのなかの5行目と9行目を表示する。

awkで5行目と9行目を表示する
$ ls -l /usr/bin | awk '{print $5,$9}'
24576 .
155 ..
37256 [
107744 a2p
28712 ac
15640 acpi_listen
28968 addr2line
29 alias
略

できた!
ちなみに行指定の間に , を入れないでスペースで空けると、

$ ls -l /usr/bin | awk '{print $5 $9}'
24576.
155..
37256[
107744a2p
28712ac
略

となる。
きゅってなって見づらいから,つけたほうがいいね('_')!
まってこんなの前にどっかでやったことあるな!
区切り文字がある内容のファイルで指定した列だけを抽出した

$ cut -d 区切り文字 -f フィールド(列)指定 ファイル名

ににてる!cutコマンドでも同じように出来るかな?って思いやってみたんだけどスペース区切りの指定の仕方がうまくできなかった。。。_| ̄|○

できなかった↓
$ ls -l /usr/bin | cut -d ' ' -f 5,9

ちがうの?

逆にcutコマンドでやってみた中身が:で区切られているファイルを

めっちゃ区切られているファイル
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin略
awkで:で区切られている内容のファイルを列指定で参照できる?やってみた。
$ cat /etc/passwd | awk '{print $4,$5}'
何も表示されなかった...

区切り文字がある時は
cutコマンド、
区切り文字がない時は
awk {print ...}
でしか表示されないのかな?('_')
ともかく、awkコマンドの列指定は
$列指定
となる。

こんな感じ!↓
               ↓$3         ↓$5    ↓$7        ↓$9
-rw-r--r--  1 root root     0 Jan  2 13:20 .bash
↑$1        ↑$2      ↑$4       ↑$6     ↑$8

ちなみに最後の列(一番右)を指定するときは
$NF
となる。

$ ls -l /usr/bin | awk '{print $NF}'
.
..
[
a2p
ac略

最後だけ出てきた!
最後の列から2番目を指定したい時は

$ ls -l /usr/bin | awk '{print $(NF-1)}'

と指定する。()で囲むんだね('_')

■パターンの指定

awkコマンドの書式
$ awk 'パターン{アクション}' ファイル

そういえばパターンはどこ行ったの('_')
そっか、↑の列指定ではパターンを省略して全行がアクションの対象になっていたんだね。
そう!パターンって誰!
「awkコマンドでは、こんなパターンだったらこのようにアクションしなさいと指定できる。」
そのパターンさんってそのパターンなんだね^^
文字列のパターンを指定するにはやはり正規表現を使う。
awkで正規表現を使うには/で囲って指定する。
指定したフィールドに対して、正規表現がマッチするかどうか指定するのには
~
を置く。

パターン書式
$ awk '$フィールド ~ /正規表現/ {アクション}' ファイル
      ------------------------
      ↑パターンの部分
ls -lの結果で9列目でcpから始まる列があれば、5行目と9行目を表示せよ
$ ls -l /usr/bin | awk '$9 ~ /^cp/ {print $5,$9}'
146880 cp
141824 cpio
67920 cpupower

できた!
ちなみにフィールドを指定しなくてもぜんぜんOKで、そのときは~も必要ない。

ls -lの結果で"l"(シンボリックリンク)から始まる列があれば、5行目と9行目を表示せよ
$ ls -l /usr/bin | awk '/^l/{print $5,$9}'
20 ansible
20 ansible-2
7 ansible-config略

一瞬まとめ

パターン書式
《パターンに行を指定する時》
$ awk '$フィールド ~ /正規表現/ {アクション}' ファイル
《パターンに行を指定しない時》
$ awk '/正規表現/ {アクション}' ファイル

パターン!アクション!ファイル

まとめ

長いから続く^^

Discussion