記事検索
月別アーカイブ
アクセスカウンター

    タグ絞り込み検索

    awk

    2014年03月26日12:54awkのフィールド参照について

    awkは$1,$2とかで入力行のフィールドを参照できるが、$iのように変数はつかえないと思っていた。というのはshではできないから。

    % cat foo
    echo $1
    I=1
    echo ${$I}
    % sh foo xxx yyy
    xxx
    foo: ${$I}: Bad substitution
    %
    

    awkだとこんな感じ。

    % echo xxx yyy | awk '{ I=1; print $I }'
    xxx
    % 
    

    awkはCに似せているだけあって値のセマンティックスなのにたいして、shはマクロ展開が基本なのでいろいろ違って当然なのだが、いったいどういう文法になっているのかFreeBSDのawkのソースコード(/usr/src/contrib/one-true-awk)をのぞいてみた。

    構成はlex.cが字句解析でawkgram.yがYACCをつかった構文解析になっている。

    lex.cを '$' で検索すると目的の箇所はすぐに見つかって、awkgram.yとあわせてみると$は優先度の高い演算子(INDIRECT/IVAR)として扱われていて還元規則が INDIRECT term となっているため、何でもかけると思ってよいだろう。したがってふつうに $1, $2, $variable かけるのはまったくとうぜんなのであった。

    lex.cをみるとなぜか$NFは$(NF)として扱われているが、これは /* very special */ とコメントがかいてあるが、意味は理解できなかった。

    $func(xxx)とか$array[idx]も特別扱いされているようだ。

    % echo a b c | awk 'function f(x) { return x-1 }; { print $f(NF) }'
    b
    %
    

    関数引数も特別扱いされている。以下例でいうと関数fで引数xをつかって$xで参照しているところだ。awkには変数宣言がないので変数のスコープはグローバル変数か関数引数のどちらかしかないためこのような扱いが必要になっているようだ。

    % echo a b c | awk 'function f(x) { return $x }; { print f(NF-1) }'
    b
    %
    

    下のように書くとxはグローバル変数になるためだ。

    % echo a b c | awk 'function f() { return $x }; BEGIN{x=2}; { print f() }'
    b
    % echo a b c | awk 'function f(y) { x=y; return $x }; { print f(NF-1) }'  
    b
    %
    

    関連リンク:

    koie



    このエントリーをはてなブックマークに追加
    2012年02月05日15:23awkのfflushポイント

    awkにはpipeでつないで外部コマンドをフィルタとしてつかう機能がある。

    awkプロセスとフィルタプロセスの両方が標準出力に書くようなときにはfflushを適切に呼ばないとだめだよなぁとおもって調べてみたら、いくつか自動でfflush(3C)を呼んでくれるようだ。

    FreeBSDの/usr/src/contrib/one-true-awkをみてみる。fflush()してるのは以下のところ:

    • FATAL/WARNING: エラーメッセージを出す前にfflush(3C)。
    • getline: 読む前にfflush(stdout)。コメントには /* in case someone is waiting for a prompt */ とあるのでプロンプトを出してユーザからの入力待ちのときにflushしたいという意図か。
    • printf: パイプで外部プロセスに渡している場合はprintfするたびにfflush(fp)するようだ。
    • system: system(3C)の前にfflush(stdout)
    • fflush: fflush()かfflush("")なら全fpをfflush(3C)して、openしているfileが指定されたらそれだけをfflush(3C)
    • print: リダイレクトしている場合にfflush(3C)する。
    • openfile(): openfileはawkの中でファイルやプロセスに関連づけられたfpをとってくるのにつかわれる関数で、fopen(3C)やpopen(3C)する直前にfflush(3C)している。

    GNU AWKにinfoにもfflushについて書いてあって

    らしい。



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