LoginSignup
9
17

More than 5 years have passed since last update.

Linux文字列操作学習:awk

Posted at

Linuxで文字列を操作しデータを整形する方法について、各手法の特性や基本的な文法などを確認する。
今回はawkについて。

■awkについて

awkはインタプリタとして、後ろに続くシングルクォートで囲まれたAWKスクリプト、
あるいはテキストファイルとして既に記述されているAWKスクリプトを解釈し実行する。

ex1
awk '{ print $1 }' /var/tmp/address.txt

これで、/var/tmp/address.txtを入力ファイルとし、シングルクォートで囲まれたスクリプト
「各読み込み行の1フィールド目を出力する」
を実行する。
構文については後述する。

シングルクォートで囲まれたスクリプト部を外部ファイル化して実行することもできる。
その場合は、ex2のようにawkコマンドに続いて-fオプション、スクリプトファイル名、(入力ファイル)の順で指定する。

ex2
awk -f test.awk /var/tmp/goods.txt

 

AWKの言語としての特性では、入力された文字列に対し行単位でパターン一致判定を行い
該当行に対し処理を実行することに長けている。

例として、
「入力されたCSVファイルのレコードの内、7フィールド目の値が"A"であるもののみ出力する」
などの処理についてはAWKを用いると容易に実行できる。

■基本的構文

コマンドとしてのawkコマンドの基本的構文はex1でも例示したように、以下のような形である。

awk '(スクリプト内容)' (入力ファイル)

これで、(入力ファイル)に対し(スクリプト内容)を実行することができる。

AWKスクリプトの基本的な構成については以下の通りである。

(パターン1){(アクション1)} (パターン2){(アクション2)}…

各行に対し、左から順にパターン一致判定を行い、
一致した(条件に合致した)行に対して波括弧内の各アクションを実行する。

また、スクリプト文中では\$n(nは数値)を使用することで、行中の各フィールドを指定できる。
\$0は行全体を表し、以降\$1,\$2...とフィールド番号を指定できる。
(なお、デフォルトでは読み込んだ文字列に対しスペースまたはタブをセパレーターとしてフィールドが分けられる。)

■パターン文について

パターン文については、正規表現あるいは比較演算子などを用いた真偽判定文などが利用できる。

真偽判定文の中では、"==" , ">=" , "!=" などの一般的な演算子のほかに、
"~"を演算子として用いることで正規表現でのマッチング判定を行うことができる。

また、"&&" , "||" を用いることで、AND,OR条件での判定を行うこともできる。

なお、波括弧の前に何も書かない場合、入力された全行に対して波括弧内のアクションを行う。
 

ex3
awk '/^2/{print $2}' /var/tmp/age.txt

波括弧の前に正規表現を記述した場合。
ex3の場合、age.txtのうち、行頭が2の行の2フィールド目を出力する。
 

ex4
awk '$2 == "山田"{print $0}' /var/tmp/employee.txt

波括弧の前に真偽判定文を記述した場合。
ex4の場合、employee.txtのうち、2フィールド目が"山田"である行の全行を出力する。
 

ex5
awk '$1 ~ /[0-9]+/{print $1}' /var/tmp/job.txt

波括弧の前に、真偽判定文に正規表現を組み込んだ判定分を記述した場合。
ex5の場合、job.txtのうち,1フィールド目に数値を含む行の1フィールド目を出力する。

 
その他に、"BEGIN"句、"END"句を波括弧の前に記述することで、スクリプト処理の最初と最後に必ず行う処理を組み込むことができる。
処理前の初期化や、最後の合計表示などに使用する。
 

ex6
awk 'BEGIN{num = 0} {num = num + $1} END{print num}' /var/tmp/price.txt

ex6の場合、price.txtの全行の1フィールド目を足し合わせた数を出力する。

■アクション文について

Cをベースにしたいくつかのコマンド・制御構文が利用できる。
print(出力)、if(条件分岐)、for(ループ)などが利用できる。

また、セミコロンを用いて処理を区分し、一行に複数処理を記載することができる。

文字列の結合については、スペース区切りで並べるだけでよい。

ex7
awk 'BEGIN{num1=0;num2=0} {if($1>60) num1=num1+$1; else num2=num2+$1} END{print num1,num2}' /var/tmp/score.txt

ex7の場合、score.txtの全行に対し、1フィールド目の値が60より大きければnum1に加算、60以下であればnum2に加算し、最後にnum1,num2を出力する。
 

ex8
awk '{for(i=0;i<10;i++){print i}}' /var/tmp/text.txt

ex8の場合、text.txtの行数回、0から9までの数値を出力する。

■その他

引数として"-F"を指定し、続けてセパレータ文字を指定することで、入力ファイルを指定したセパレータで分割し読み込む。

ex9
awk -F"," '{print $1}' /var/tmp/name.csv

ex9の場合、入力された"name.csv"をカンマ区切りで読み込み、各行の1フィールド目を出力する。

また、AWKスクリプト文中ではいくつかの組み込み変数が利用できる。
例として、"NF"は現在読み込み行のフィールド数、"NR"は現在読み込み行までに入力された行数を示す。

ex10
awk '{print NR ":" NF}' /var/tmp/food.txt

ex10の場合、入力されたfood.txtの各行について、「(行番号):(その行のフィールド数)」を出力する。

 

今回は基本的な部分のみということで以上。
他にも多くのコマンド、組み込み変数が利用できる。

(参考サイト)
http://shellscript.sunone.me/awk.html
http://www.kt.rim.or.jp/~kbk/gawk-30/gawk_1.html

9
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
17