ここから本文です

【 awk 】コマンド(応用編その2)――テキストの加工とパターン処理、関数の活用とCSV

6/23(金) 8:40配信

@IT

 Linuxの基本的なコマンドについて、基本的な書式からオプション、具体的な実行例までを分かりやすく紹介していきます。今回は、テキストのパターン処理を行う「awk(gawk)」コマンドです。本稿では、awkの応用を説明します。

awkコマンドでCSVファイルを加工したところ

●awk(オーク)コマンドとは?

 「awk」は空白などで区切られたテキストを処理するコマンドです。演算機能もあり、プログラミング言語としても使用されています。

 Linux環境で使用されているのは、GNUプロジェクトによる「gawk」コマンドが多く、例えばCentOS 7の場合、awkは/usr/bin/gawkへのシンボリックリンクとなっています。

 Ubuntu 15では、Michael D. Brennan氏による「mawk」が収録されています(awkは/etc/alternatives/awkへの、/etc/alternatives/awkは/usr/bin/mawkへのシンボリックリンク)。

 どちらも、もともとのawkに加えてPOSIX 1003.2への準拠や組み込み変数、正規表現指定のバリエーションなどが拡張されています。


●awkコマンドの書式

awk [オプション] [コマンド] [ファイル……]

※[ ]は省略可能な引数を示しています


●awkの主なオプション

短いオプション/意味
-f ファイル名/awkスクリプトが書かれたファイルを指定する
-F 区切り文字/区切り文字を指定する(デフォルトは空白文字)
-v 変数名=値/変数を定義する

※gawk(GNU版awk)の場合、長いオプションも使用可能。-fは--file program-file、-Fは--field-separator、-vは--assign。gawkにはこの他にも多数のオプションがある。

●awkで使用できる主な組み込み変数

変数名/意味
ARGC/引数の個数
ARGV/引数(配列)
ENVIRON/環境変数を収めた連想配列。例えば環境変数LANGならばENVIRON["LANG"]と参照できる
FILENAME/現在処理しているファイルの名前
FNR/現在処理しているファイルのレコード番号(処理しているファイルが1つの場合はNRと同じ値になる)
FS/フィールドの区切り文字(-Fオプションで変更可能、デフォルトはスペース)
NR/現在処理しているレコード番号(行番号)
OFS/出力時のフィールドの区切り(デフォルトは空白)
ORS/出力時のレコードの区切り(デフォルトは改行)
RS/レコードの区切り(デフォルトは改行)


●awkで使用できる主な文字列操作用の関数

関数(引数)/意味
gsub(r, s, t)/「文字列t」中で「正規表現r」にマッチした箇所全てをsに置き換えて、置き換えた個数を返す。tを指定しなかった場合は「$0」(読み込んだ行全体)が対象
index(s, t)/「文字列s」に含まれる文字列tの位置を返す。tが含まれていない場合は0を返す
length(s)/「文字列s」の長さを返す。sを指定しなかった場合には「$0」の長さを返す
match(s, r)/「文字列s」で「正規表現r」にマッチする位置を返す。その際、内部変数のRSTARTに開始位置、RLENGTHに長さをセットする。マッチしない場合は0を返す
split(s, a, r)/「文字列s」を「正規表現r」で分割し、配列aに格納する。rを省略した時は「FS」(区切り文字、デフォルトは空白)となる
sprintf(フォーマット指定, 変数リスト)/フォーマット指定に従って整形した文字列を返す。指定方法は「printf」(第118回)と共通
sub(r, s, t)/「文字列t」の中で「正規表現r」へ最初にマッチした箇所をsに置き換える。tを指定しなかった場合は「$0」が対象
substr(s, i, n)/「文字列s」のi文字目からn文字分を返す。nを省略した場合はi文字目以降全てを返す
tolower(s)/「文字列s」のうち大文字を全て小文字に変換したものを返す
toupper(s)/「文字列s」のうち小文字を全て大文字に変換したものを返す

※この他、sin()やlog()、rand()などの数値関数、さらにgawkの場合はsystime()やmktime()などの時間関数を利用できる。


●文字列を置き換える

 awkでは処理内容を「パターン{アクション}」と指定します。パターンに合致した行に対し、アクションを実行する、という意味です。パターンを省略した場合は全ての行に対してアクションを実行します。

 アクション部分では、文字列を加工する「関数」を利用できます。例えば、文字列の置き換えならば「sub関数」と「gsub関数」があります。

 sub関数は「sub("置換前文字列", "置換後文字列", 対象)」のように指定します。対象を省略した場合は「$0」つまり“行全体”という意味になります。なお、置換前文字列の部分には正規表現を使用できます。

 gsub関数の引数はsub関数と同じで、違いは置換する個数です。sub関数は最初の1つだけ、gsub関数は対象範囲にあるもの全てが置換の対象となります。

 以下のコマンド例では、/etc/shellsの全ての行を対象に、小文字のinを大文字のINに置き換えています。コマンド実行例では読みやすくするために{}前後などに空白を入れていますが、画面では入力を省略しています。

――――――
●コマンド実行例
cat /etc/shells | awk '{ sub("in", "IN"); print }'

cat /etc/shells | awk '{ gsub("in", "IN"); print }'
――――――

 同じ処理をsedコマンドの「s」スクリプトコマンドを使って書き換えると次のようになります。

――――――
●コマンド実行例
cat /etc/shells | sed -e "s/in/IN/"

(sub()相当)

cat /etc/shells | sed -e "s/in/IN/"g

(gsub()相当)
――――――

●CSVデータを扱うには

 CSVファイルでは「,」記号でデータを区切っています。awkのデフォルト区切り文字は空白なので、CSVのフィールドを取り扱う場合は区切り文字を「,」に変更する必要があります。

 起動オプションで区切り文字を指定する場合は「-F」オプションを使い、「-F ","」あるいは「-F,」のように書きます。

 以下のコマンド例では、CSVファイルに対し、2つ目のフィールド($2)が「食器」の場合、金額($4)と「,」記号、品目($3)を出力しています。

――――――
●コマンド実行例

awk -F "," '$2~/食器/ { print $4 "," $3 }' ファイル

cat ファイル | awk -F "," '$2~/食器/ { print $4 "," $3 }'
――――――

●出力する際の区切り文字を変更するには

 「-F」は入力の区切り文字を変更します。これに対し、出力の区切り文字を変更したい場合は変数「OFS」を使います。他の出力に先立って変更する必要があるため、「BEGIN」の中で指定します。

 例えば、以下の処理では、先ほどのCSVファイルに対して、「金額が500以上のものだけについて、ID中の文字Aを文字Xに置換」します。

――――――
BEGIN {
FS=","   #入力の区切り文字を「,」にする
OFS=","   #出力の区切り文字を「,」にする
}
{
if ($4>=500) sub("A", "X", $1)   #金額($4)が500以上ならID($1)のAをXに置換
print
}
――――――


 処理が短いので、コマンドライン実行例のように指定することもできます。上の例では入力の区切り文字を-Fオプションで、下の例では入力出力ともにBEGINの中で設定しています。

――――――
●コマンド実行例

$ cat list1.csv | awk -F, 'BEGIN{OFS=","} {if($4>=500)sub("A","X",$1);print}'

$ cat list1.csv | awk 'BEGIN{FS=","; OFS=","} {if($4>=500)sub("A","X",$1);print}
――――――

 OFSを用いず、「-F」だけで区切り文字を変更した場合、不完全な形に終わります。出力時の区切り文字を見ると、加工していない行は「,」ですが、加工した行は空白文字になってしまいます。

――――――
●コマンド実行例
$ cat list1.csv | awk -F, '{if($4>=500)sub("A","X",$1);print}'
――――――

 awkコマンドと似た処理を他のコマンドの組み合わせで実行することもできます。例えば指定したフィールドだけを出力する場合、cutコマンドを利用できます。

 今回の場合は「grepコマンドで行を絞り込み、その後cutコマンドで必要なフィールドだけを抽出する」という方法でもうまくいきそうです。ただし、cutコマンドの場合は項目の出力順を変更できません。出力内容を絞るだけではなく、加工までしたいならば、sedまたはawkが向いています。


●筆者紹介

西村 めぐみ(にしむら めぐみ)

PC-9801NからのDOSユーザー。PC-486DX時代にDOS版UNIX-like toolsを経てLinuxへ。1992年より生産管理のパッケージソフトウェアの開発およびサポート業務を担当。著書に『図解でわかるLinux』『らぶらぶLinuxシリーズ』『はじめてでもわかるSQLとデータ設計』『シェルの基本テクニック』など。2011年より、地方自治体の在宅就業支援事業にてPC基礎およびMicrosoft Office関連の教材作成およびeラーニング指導を担当。

最終更新:6/23(金) 8:40
@IT