awkについての覚え書き1

awk

文字列が大量に記載されている TXT や CSV ファイルなどを処理したい場合

もちろん CSV あたりなんかは業務でお馴染みのエクセル君に読み込ませて操作するもいいでしょう



ただエクセル君もあれでなかなか処理の重さを持つシャイボーイ君なので

文字列さんに対してどれだけフットワーク軽いんだと思わせるほどの処理の軽さを誇る awk について書いておこうと


そもそも UNIX や Linux と呼ばれる通称 CUI の OS 上での行動を生業としている人には馴染み深すぎるでしょう

ただ最近思ったのが知らない人は使い方をあまり把握していないっぽいことがあったので自分がそうなってもいいようにそのメモとして

まず awk の整理から

awk とは

UNIX/Linux 使っている人にとっては馴染み深いとはさっき書きましたが

コマンドでの使用も多くなってくると awk がプログラミング言語だということを忘れがちになります

awk は立派なプログラミング言語です

ただしプログラミング言語といってもテキスト処理を目的としたプログラミング言語なので巷で話題の Python みたいな汎用プログラミング言語とは少々趣が違います

最近のリソースが溢れる時代と違い awk が生まれた時代はプログラミング言語そのものもより小さくより軽くを求められていた背景があったためにこのような一極集中型の力を持ったプログラミング言語になっている模様

本来なら Perl も awk と同じタイプだったみたいですがあちらは上手く転身したために今となっては汎用側の方に陣取っていますね

と覚えていたら awk も要望があって汎用に見紛うレベルで拡張を施されているらしい、、、

知らんかった、、、

少し話逸れました

Re: awk とは

awk は先に書いたようにテキスト処理を目的にしたプログラミング言語です

特に空白やカンマなど何かしらの規則を持って行の内部を区切っているテキストタイプに対してより明確に強力さを発揮してくれる

元々は grep(文字列検索)、sed(文字列操作)の拡張として生まれました

awk を純粋なプログラミングとして使用するよりもコマンドの延長にちょっと使用するとかなら grep や sed それから tr 辺りで十分じゃんなんて思われてたりもする悲しい存在です

そんな awk だからこそいざというときに使い方忘れてたりとかあるみたい

便利なんだけどな

プログラミングするレベルで書いとくと最初の覚え書きの一つとなるならあまりにどうかなと思い簡単なところから

awk使用例

動かすだけなら簡単に動かせます

awk '{ 処理内容 }' 読み込ませるファイル

または

awk '(条件式){ 処理内容 }' 読み込ませるファイル

極端な話としては上記の2例を基本とするだけでもだいたいの意図に沿って動かせます


例えばこのような状態の行が数十行どころか数百行や数千行出てくるファイルがあったとしましょう

市場第二部(内国株),陸運業,9029,ヒガシトゥエンティワン,2021/12/1,650,651,668,643,664,21500,0,0,126800,22,2022/3/30,9.22,0.93
市場第二部(内国株),陸運業,9028,ゼロ,2021/12/1,1037,1029,1048,1025,1048,700,0,0,40300,45.7,2022/6/29,5.72,0.62
市場第二部(内国株),輸送用機器,7315,IJTT,2021/12/1,529,527,535,523,525,56700,0,0,375100,20,2022/3/30,4.56,0.33
市場第二部(内国株),輸送用機器,7299,フジオーゼックス,2021/12/1,3115,3100,3110,2960,3045,2300,0,0,55800,130,2022/3/30,6.58,0.23
市場第二部(内国株),不動産業,3241,ウィル,2021/12/1,368,366,375,364,366,12900,0,0,241600,14.5,2021/12/29,7.68,1.28
市場第二部(内国株),不動産業,3238,セントラル総合開発,2021/12/1,322,320,321,317,317,4900,0,0,344100,12,2022/3/30,5.57,0.41
市場第二部(内国株),非鉄金属,5816,オーナンバ,2021/12/1,525,525,532,510,529,55700,0,3800,615900,12,2021/12/29,6.44,0.37
市場第二部(内国株),非鉄金属,5781,東邦金属,2021/12/1,1080,1080,1101,1053,1101,25200,0,0,189700,0,2022/3/30,6.22,0.94
市場第二部(内国株),非鉄金属,5729,日本精鉱,2021/12/1,3575,3505,3600,3435,3600,900,0,0,36000,100,2022/3/30,7.32,1
市場第二部(内国株),電気機器,6998,日本タングステン,2021/12/1,2163,2150,2168,2127,2141,2400,0,0,47700,100,2022/3/30,6.88,0.49
市場第二部(内国株),電気機器,6969,松尾電機,2021/12/1,870,880,890,821,872,71700,0,2400,485400,0,2022/3/30,8,1.21
市場第二部(内国株),卸売業,7460,ヤギ,2021/12/1,1390,1380,1382,1374,1380,1200,0,0,422300,48,2022/3/30,7.41,0.32
市場第二部(内国株),卸売業,3143,オーウイル,2021/12/1,1109,1072,1086,1067,1068,15200,0,0,92200,45,2022/3/30,7,0.94
市場第二部(内国株),医薬品,4595,ミズホメディー,2021/12/1,2407,2448,2469,2375,2381,244500,0,0,582300,145,2021/12/29,4.92,3.78
市場第二部(内国株),パルプ・紙,3945,スーパーバッグ,2021/12/1,1606,1630,1630,1450,1496,6900,0,0,59500,0,2022/3/30,0,0.77
市場第二部(内国株),サービス業,9791,ビケンテクノ,2021/12/1,911,912,912,902,902,900,0,0,409900,20,2022/3/30,5.96,0.38
市場第二部(内国株),サービス業,9767,日建工学,2021/12/1,1870,1840,1860,1840,1860,500,0,0,37500,30,2022/3/30,8.07,0.96


乗っている例としてはカンマ区切りの内容ですとこのような情報です

市場,業種,銘柄コード,名称,現在日付,前日終値,始値,高値,安値,終値,出来高,逆日歩,信用売残,信用買残,配当,配当落日,PER,PBR


でその時の条件がカンマを区切りとしたとして左から2つ目にある項目が”サービス業”だったら取得したいと

単純に grep “,サービス業,” としても取れますけどもそれだと他の項目にもサービス業の文字が入っていると

その行まで取得してしまい返って排除することまで入れたりと手間が増えるのできっかり2つ目のみで判定させたい
※上の例にはどの行にも左から2つ目以外にサービス業はないので grep でいけますが他の行にはある前提として進めます


そんなときにエクセル君にお願いするよりかは awk にお願いしちゃいましょうと

例で示した方法に少し足した次の形で成せます

awk -F',' '($2 == "サービス業"){ print $0 }' 

これだけです

ちょっと説明として

awk のオプション

まず -F’,’ について

awk の前提として読み込むファイルの区切りを空白を標準設定としています

ですが今回の読み込みファイル対象がカンマを区切りとする CSV ファイルのため

区切りを空白からカンマに変更する指示が必要でした

そのときに awk にその指示をするのが -F で区切りを変更する宣言とそのすぐ後に空白もなくくっつけて示す ‘,’ の存在です

これにより今さっきの awk 文は読み込んだファイルの区切りをカンマと認識して処理を進めます

※当然ながら他にオプション( -v による変数宣言と値渡しとか)は色々ありますが一旦これ


それによりカンマ区切りの左から2つ目のサービス業だったらの ($2 == “サービス業”) が有効になります

awk の標準機能

awk は行を読み込むと $1、$2、$3 と区切られた単語ごとに値を保持します

($2 == "サービス業")

これは結果だけ言うと区切りの2項目が”サービス業”だったらの判定式を示しています

先の書いた $2 がまさにカンマ区切りの左から2つ目である証左です

では $0 は何かと言うとその該当行全体となります

区切っていない状態のことです

なので

表示させる機能 print に $0 を渡してやるだけで左から2つ目に目的の文字がある行だけを抜き取ってくれますとなります



ちなみに今回は左から2つ目の項目をとしましたがさらに他にも左から5つ目にも絞りたい文字があった場合は繋げることもできます

($2 == "サービス業" || $2 == "不動産業")

実は”サービス業だけじゃなくて左から2つ目が”不動産業”の場合も対象としたい場合

の場合は左から2つ目が”サービス業”または(これが”||”の役目)”不動産業”の行だけとしたいだったり

他に

($2 == "サービス業" && $5 == "YYYY/MM/DD(絞りたい日付)")

今回は左から5つ目は日付なので日付を例として記載しています

この場合は左から2つ目が”サービス業”且つ(これが”&&”の役目)左から5つ目が”特定の日付”になる行だけとしたいだったり

なんてことも手軽にできます





今回は

{ 処理内容 }

{ print $0 }

だけの形にしていますがここには if(){}else{} も for でも入れられます
書き方が一行野郎形式なので紛らわしいかもですが

'{
    if ( 条件式 ) {
        print $0
    } else {
        print $2
    }
}'

このような形でも記述できるのである程度プログラミング言語と納得いただけるかなと





今回は awk の初歩の初歩をメモとしましたがまだまだ他にもあるので覚え書きするたびに増やして置いておければ

後で自分が awk のあれがーってなったときに役立つので残したい、、、

コメント