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

本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、テキストのパターン処理を行う「awk」コマンドです。

» 2017年06月22日 05時00分 公開
[西村めぐみ@IT]
「Linux基本コマンドTips」のインデックス

Linux基本コマンドTips一覧

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

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では処理内容を「パターン{アクション}」と指定します。パターンに合致した行に対し、アクションを実行する、という意味です(第115回)。パターンを省略した場合は全ての行に対してアクションを実行します。

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

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

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

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

コマンド実行例

cat /etc/shells | awk '{ sub("in", "IN"); print }'画面1

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


画面1 画面1 sub関数(上)とgsub関数(下)を実行したところ

 画面1と同じ処理をsedコマンドの「s」スクリプトコマンドを使って書き換えると次のようになります(sedコマンドについては第53回第57回参照)。

コマンド実行例

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)を出力しています(画面2)。パターンの指定方法については第116回、printについては第118回を参照してください。

コマンド実行例

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

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


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


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

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

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

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

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

 スクリプトファイルとして実行する場合は第117回を参照してください。

コマンド実行例

$ 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}'画面3


画面3 画面3 出力時の区切り文字を変更して処理したところ

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

コマンド実行例

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


画面4 画面4 OFSを用いないと目的とは異なる出力になってしまう

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

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



筆者紹介

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

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


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。