SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

USP MAGAZINEコラボレーション連載/「シェル芸」に効く AWK処方箋

簡単で、奥深くて、超便利!
LLの元祖「AWK」にさわってみよう

► 「シェル芸」に効く AWK処方箋 第1回 (月刊『USP MAGAZINE 2014 April(Vol.12)』より転載)


  • X ポスト
  • このエントリーをはてなブックマークに追加

代入演算子

 代入演算子にも真偽があります。一部のAWKの実装で加わった特殊な変数を除きAWKの代入は破壊的に代入できますので、代入が成功しているから必ず真を返すという誤解をしていませんか? AWKでは代入の可否と戻り値は関係ありません

 では、以下のようなもので第2フィールド編注2を"B"にしてみます。

$ echo "a b c" | awk '{$2 = "B"; print $0}'
a B c

 問題ないですね。代入が常に真であるなら、以下のようにパターンに記述することができます。

$ echo "a b c" | awk '$2 = "B"'
a B c

 これだけを見ると、代入の可否が真偽を表しているように思われるかもしれません。では、第2フィールドに空文字列を代入して第2フィールドを削除したいとします。

$ echo "a b c" | awk '{$2 = ""; print $0}'
a c

 同様に以下のようにして第2フィールドを削除してみます。

$ echo "a b c" | awk '$2 = ""'

 何も出ませんね。エラーもないことから、代入そのものは成功しているのでしょう。このパターンに記述した代入がうまく動作しないのは代入の戻り値が代入の真偽ではないからです。

 そこで、以下のようにprint文で代入の戻り値を確かめてみましょう。
$ echo "a b c" | awk '{print $2 = "B"}'
B
$ echo "a b c" | awk '{print $2 = ""}'

 お分かりになりましたか。代入の戻り値は左辺値だったのです。先ほどの第2フィールドを削除するものをパターンだけで記述したい場合には、例えば以下のようにします。

$ echo "a b c" | awk '!($2 = "")'
a c

つまり、代入には成功しているものの、代入演算子が空文字列を返してしまい、レコードが表示されないということなので、戻り値を"!"で反転してやれば良いわけです。否定演算子"!"は真偽を反転する演算子です。

 また、よく使われる手法として$1だけを表示するには以下のように$0に代入します。

$ echo "a b c" | awk '$0 = $1'
a

 この真偽は、$0に数字の0または空文字列が代入されない限り、真になります。

編注2:AWKでは何もしなくても、行からある文字(デフォルトでは半角空白とタブ文字)で区切られた「フィールド」を取り出せます。変数$1、$2……がそれぞれ第1フィールド、第2フィールド……を参照するルールになっており、"a b c"という行なら、print $2ではbが表示されます。$0は行全体です。

変数

 AWKにはいくつかの組込変数があります。代表的なものには現在のレコード数を示すNR(Number of Record)と現在のレコードの中のフィールド数を示すNF(Number of Field)があります。これらはパターンの中でよく用いられます。例えば、フィールド数が3のものを表示したい場合には以下のようにします。

$ echo "a b c" | awk 'NF == 3'
a b c

 前述の比較演算子により真偽判定が行われています。一方、間違って以下のようにするとどうなるでしょうか。

$ echo "a b c" | awk 'NF = 3'
a b c

 この場合には代入演算子の真偽が左辺値なので、NFに数字3が代入されて、パターンの値は数字の3になり、結果としてパターンは真になってしまいます。つまり、結果として同じでも真偽の対象が異なってしまうのです。

 このNFを用いた記法には癖があります。GNU AWKやmawkで第1フィールドから第2フィールドまでを出力したい場合には以下のようにできます。

$ echo "a b c" | awk 'NF = 2'
a b

 NFに数字の2が入ってしまいますので、AWKはフィールド数が2であると解釈して$1から$2までを表示しますが、AWKの実装に依存しますので、この記法には注意してください。

 さて、NFの真偽を使った便利な使い方があります。

$ echo "\n a \n b \n \n" | awk 'NF'
a
b

 分かりましたか。NFにはフィールド数が格納されますが、スペースやタブだけの行、空の行のようにフィールドがない場合には値が数字の0になるためパターンは偽となり、結果としてスペースやタブだけの行や空の行を削除できます。「シェル芸」勉強会でも何度か登場していますが、意外に便利です。

関数

 関数とは何でしょうか。中学や高校で習う関数と同じように、AWKの関数は一価関数と言われ、戻り値は1つです。この関数の戻り値を使った真偽判定を行うこともできます。

 length関数は文字数(バイト数ではない)を返す関数ですが、引数がないと$0を用い、しかもその場合には丸括弧も不要という、ちょっと変わった関数です注4

$ echo "\n a \n b \n \n" | awk 'length'
a
b
 ←スペースだけの行が出力されている

 先ほどのNFを用いた場合にはスペースやタブだけの行は削除されましたが、レコードに今度は何らかの文字があれば表示されるようになります。

 関数は戻り値があるので分かりやすいのですが、よく間違えるものにsub()関数とgsub()関数があります。sub()関数は置換に成功すれば数字の1を返して失敗すれば数字の0を返し、gsub()関数は置換に成功した個数を返します注5

$ echo "a b c" | awk '{print gsub(/a/, "")}'
1

 したがって、マッチする箇所を数えるには以下のようにすれば良いわけです。

$ echo "ab ba ab" | awk '$0 = gsub(/ab/, "")'
2

 マッチしない場合には数字の0をgsub()関数は返すのですが、数字の0は偽であるため、何も表示されず0と表示されません。でも、0と表示させたいですね。この場合には以下のようにします。

$ echo "ab ba ab" | awk '$0 = gsub(/ac/, "") ""'
0

 gsub()関数は数字の0を返しているのですが、数字の0は偽になります。ところが空文字列を連接してあげることで文字列の0の扱いになります。文字列の0は偽にはならないのです。

 フィールドをそれぞれ配列にしたいような場合には以下のようにします。

$ echo "ab ba ab" | \
  awk 'split($0, arr) {print arr[1]}'
ab

 split()関数は分割個数が戻り値になりますので、このような使い方ができるわけです。

注4:この引数も括弧もないlength関数の取り扱いは議論されていて、将来的に廃止になるかもしれません。
注5:置換後の文字列を返すには、GNU AWKであればgensub()関数が用意されていて、後方参照による置換も可能な高機能関数となっています。

まとめ

 AWKの真偽を使った例をいくつか挙げながら、真偽について深く掘り下げてみましたが、いかがでしたか。やっぱりAWKは呪文だと思われた方、AWKはパターンとアクションの言語であり、そのパターンは真偽値で判断されるということを知っているだけで様々なことができると思われた方などがいらっしゃると思いますが、今回例として挙げたAWKスクリプトは長くても20文字程度ですので、頭の中で良く考えてみてください。

 最後に、「シェル芸」勉強会に筆者はできるだけ参加しています。勉強会は講習会でも授業でもありませんので、積極的に質問をしてみてください。質問をするということは、単に自分が答えを導き出すためのヒントや方向性を得るだけでなく、勉強会の参加者全員に考える機会を与えてくれます。これは「シェル芸」勉強会に限らない話ですので、IT関連の勉強会では積極的に質問してみましょう。

『USP MAGAZINE 2014 May(Vol.13)』は、ただいま絶賛発売中!
USP MAGAZINE 2014 May(Vol.13)

 『USP MAGAZINE』は日本で唯一のシェルスクリプト総合誌(毎月25日発売)。最新号の2014 May(Vol.13)では、新連載「アジャイル改善塾」がスタート! 著者の山海一剛さんが実体験をもとに、自身がソフトウェアアーキテクトを務めるユーザ系SI会社へアジャイル開発を導入し、組織文化を変えようと取り組む物語。涙なしには読めません!

 そのほか、エンジニアが集うトークイベント「TechLION」のレポートとして、「学内のある棟をTCP/IPで何でも管理可能にした」という江藤浩氏(東京大学大学院情報理工学系研究科教授、WIDEプロジェクト代表)の強烈なトークを収録。もちろん、本連載「AWK処方箋」の最新回もあります!

 

► お求めは、Amazon.co.jpUSP研究所のWebサイト取り扱い書店まで。

 

USP MAGAZINE 2014 May(Vol.13)

価格:500円+税

仕様:B5版 62ページ オールカラー

発行人:ユニバーサル・シェル・プログラミング研究所

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
USP MAGAZINEコラボレーション連載/「シェル芸」に効く AWK処方箋連載記事一覧

もっと読む

この記事の著者

斉藤 博文(サイトウヒロフミ)

最初にAWKと出会ってから○十年、AWKの魅力に取りつかれ、勢い余って「日本 GNU AWKユーザー会」を立ち上げています。会としてOSCなどのイベントにも出展しつつ、GNU AWKの開発も手伝っています。「USP友の会」では幹事役ですが、「シェル芸勉強会」にはほぼ毎回参加して一緒に勉強しています。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7752 2017/01/31 19:59

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング