UNIX/Linux及びシェルにおいてテキスト編集と言えばawkでしょう。
awkはその発祥こそUNIXコマンドツールですが、後に拡張され、gawk(GNU awk)含め、制御構造を備え、関数も作成できる単独のscriptです。
尚、awkにCはともかくPerlに似た機能や使い方があるのは、オープンソース文化と歴史的な背景によるものでPerlがCやawk等々を参考に開発された経緯があるからであり、またawk、find、grep、sed他多くのコマンドは、ほぼ同時期に相互に影響しあいながら誕生した経緯があります。
まず、awkの標準入力は基本的にパイプ経由のデータかファイルです(コマンドラインからファイルを指定せずEnter、改行され待機状態になるのでファイル以外の妥当なデータを入力、[Ctrl]+[D]で実行することもできますが、あまり現実的ではありません)。
$ cat file_foo
awk sed find grep
find grep awk sed
ここに入力ファイルの例として4つのコマンド名がスペース区切りで記述されたテキストファイルfile_fooがあるとします。
awkコマンドの記述の基本形は、awkに続けてスペース、続く編集式全体をシングルクォートで括り、続けて入力ファイルを記述したもので、これら全体は指示・命令を表すステートメントと呼ばれます。
$ awk ' $3=="awk" ' file_foo
$ awk ' ($3=="awk") ' file_foo
この例(の等号=は2つで比較演算子)はfile_fooの$3に当たる場所にawkという文字列がある行を標準出力に出力しますが、文字列やエスケープシーケンスには引用符が必要でawkも同じタイプの引用符で重ねて括ることはできないので文字列awkをダブルクォートで括る必要があり、他方コマンドを含まない単一の式の場合、 ( ) の有無に関わらず同じ結果になります。
$ awk ' { print $0 } ' file_foo
次にprintなどのコマンド(awkではアクションと呼ぶ)を含む場合には、シングルクォートの内側で式を { } で括り、この例はfile_fooの行全てを標準出力に表示します。
$ awk ' { if ( $3=="awk" ) print $0 } ' file_foo
これらを組み合わせて当該個所にawkという文字列がある行が表示されるこの例のようにコマンドを含む { } 内には条件式を記述することもでき、ifに続く条件式の ( ) は必須で省略不可、文字列"awk"もダブルクォートで括る必要がある一方、(お勧めはしませんが)寛容なことに?この例については { } 内でスペースを全て除去しても実行できたりします。
更にawkは、Perl同様、BEGINステートメントとENDステートメントを記述することもでき、テキスト編集加工の前処理、後処理ができるようになっています。
$ awk ' BEGIN{ ( $3=="awk" ) } { print $1 } ' file_foo
$ awk ' BEGIN{ $3=="awk" } { print $1,$2 } END{ print "end" } ' file_foo
$ awk ' { print $3 } END{ print "end" } ' file_foo
BEGINはヘッダで入力ファイルのデータ読み込み前に実行する処理を行う為に使用、コマンドや条件式の設定はしない(しても期待した結果にはならない)、ENDはフッタで後処理としてコメントの他にも小計や必要であれば入力データを利用したコマンドやコマンドを伴う条件式も記述でき、これらを記述する場合、その順序はBEGIN、メインのパターン・編集コマンド、ENDの順でBEGIN/ENDの後ろのステートメント部分も { } で括ります。
$ awk ' BEGIN{ print "header" } ' file_foo
$ awk ' BEGIN{ printf( "%c \n" , 65 ) } '
$ awk ' END{ print $1 } ' file_foo
よって単独で記述はできるものの、それだけでは意味がないものとして、1つめのBEGINは入力ファイルをとってawkを実行する意味がなく、2つめと3つめのBEGIN、ENDはそれぞれBEGINと5文字、ENDと3文字余計に入力する意味も必要もありません。
$ awk ' BEGIN{ print "calc start" } { sum += $2 } END{ print "total:"sum } ' bar.txt
calc start
total:80
$ cat bar.txt
1 20 + awk
2 30 - grep
3 20 * sed
4 10 / find
この例は、なんらかの数字や四則演算記号、awk、grep、sed、findという文字列がスペース区切りで羅列されたこのbar.txtを入力ファイルとして標準出力にcalc startと出力した後、bar.txtに記述されたセパレータ(既定のスペース)で区切られた2つめの値を(縦方向に20,30,20,10と)順次加算していきtotal:に続けて合計となる80を表示します。
尚、ここに出てくるドル記号$に0はShellやPerlと似た自動変数でawkの場合、$0には受け取った文字列などの「全体」が格納され、$1,$2,$3...$nと必要な分だけ続く位置変数パラメータという特殊な変数には、ある決まりに沿った値が順次格納されることになっています。
awkが自動的に格納する、ある決まりに沿った値とは(UNIX/Linuxコマンドにもawkにもsplitはありますが)Perlのsplit同様、一定の区切り文字・区切り記号(FS/Field Separator/フィールドセパレータ/セパレータ)によって分割される単位の値です。
$ awk -F: ' { print $2 } ' file_foo > hoge
awkの既定のセパレータはスペースで-Fオプション(スペースを入れずに-Fに続けてセパレータ)を付加することで記号、文字、数字など基本的になんでも指定することができ、この例ではコロン:を指定、file_foo内の行を順次見ていきコロン区切りの2番めの値をファイルhogeに出力します。
演算子 | 種類 |
---|---|
算術演算子 | + - * / % ^ |
代入演算子 | = += -= *= /= %= ^= |
論理演算子 | && || ! |
条件演算子 | ? |
マッチング演算子 | ? !? |
比較演算子 | < <= == ! >= > |
前置/後置演算子 | ++ -- |
awkの演算子には、算術演算子、代入演算子、条件演算子、マッチング演算子、比較演算子、increment(1加算)/decrement(1減算)における前置(prefix)演算子・後置(suffix)演算子があります。
意味 | |
---|---|
\b | 後退 |
\f | 改ページ |
\n | 改行 |
\r | 復帰 |
\t | タブ |
\ddd | 8進数 |
\c | その他エスケープ文字 |
awkステートメント内で使用できるエスケープシーケンスです。
尚、awkにおけるprint文の出力はbashのechoと同様、行末に改行付きで出力され、他方awkにはこれもbashやCのようにawk独自の書式付出力関数printfもあり、printfの場合はbashやC同様、明示的に改行を入れないと既定では改行されません。
その他エスケープ文字というのは、特殊文字にバックスラッシュを付ければ、たいていの場合エスケープできることを意味します。
メタ文字 | マッチ条件 |
---|---|
. | 何らかの1文字 |
? | 0個または1個の文字の並び |
* | 直前の文字やパターン0個以上 |
+ | 直前の文字やパターン1個以上 |
[ ] | 指定文字クラス |
^ | 行先頭 |
$ | 行末尾 |
| | 条件or |
( ) | パターンクラス |
\ | バックスラッシュ エスケープ |
awkで正規表現及びパターンとして利用できるメタキャラクタは、ブラケット[]で括られたクラス、プラス+、アスタリスク*、クエスチョンマーク(疑問符)?、ドット/ピリオド.、キャレット^、ドルマーク$、縦棒|、丸かっこ()、バックスラッシュ\です。
#!/usr/bin/awk -f
awkをスクリプトとして利用する際には、他のコマンドインタプリタ、インタプリタスクリプト同様、1行めにシャープとエクスクラメーションマーク(感嘆符) #! に続けて実行ファイルパスを記述し、awkやsedの場合、更に-fオプションを付加する必要がありますが、awkはコマンドから拡張されたスクリプトと言うよりは、Perl、Python、Rubyのようなコマンドラインでも使えるスクリプトでありながら、むしろそれら以上にコマンドラインでの使い勝手もよいと言えるほどその全容は奥深いものです。
組み込み変数 | 意味 |
---|---|
ARGC | scriptにおける引数の数 |
ARGV | scriptにおける実引数の配列 |
ENVIRON | 環境変数の一覧 |
FILENAME | 現在読み込み中のファイル名 |
FNR | 現在のファイル内カレントレコード番号 |
FS | 入力フィールドセパレータの設定 コマンドラインオプション-Fと同様 既定はスペース |
RS | 入力レコードセパレータの設定 既定は改行 |
NF | カレントレコード内のフィールド数 |
NR | 今まで読み込んだレコード数 |
OFS | 出力フィールドセパレータの設定 既定はスペース |
ORS | 出力レコードセパレータの設定 既定は改行 |
ちなみにawk scriptが入力ファイルをとる際には、-Fではなくハイフン-なしのFSをセパレータ指定オプションとして使用、またawkの編集結果は標準出力に書き出されるので結果を残したい場合にはファイルリダイレクト等を利用します。
ここでは、内容をかなり限定しましたが、これら以外についてはコマンドラインからawk/gawk、またはawk --help/gawk --help、更にman awkやinfo gawkで確認してください(help/info/man)。