tac を作ってみる

awk で tac を作る場合、普通は以下のように記述するでしょう。

#! /usr/local/bin/nawk -f
## tac.awk

{
    line[NR] = $0;
}

END {
    for (i = NR; i > 0; i--) {
        print line[i];
    }
}

このスクリプトは awk 単独であれば優れた解だと思いますが、行数だけ配列を用意する必要があるため、多くのメモリを必要とします。

そこで、今回は双方向パイプ (two-way pipe) を使ってコプロセスから値を取得してみます。

今まで双方向パイプは TCP/UDP などを使った通信の場合しか紹介していませんでしたが、コプロセスでも用いることができます。

#! /usr/local/bin/gawk -f
## tac2.awk

BEGIN {
    ## 区切は \034 とし、他の文字との競合を避ける
    sort_exe = "sort -t \"\034\" -nr"
}

{
    ## コプロセスに渡す
    printf("%d\034%s\n", NR, $0) |& sort_exe;
}

END {
    ## 入力のパイプだけを閉じる
    close(sort_exe, "to");

    ## コプロセスの出力を getline で読み取る
    while ((sort_exe |& getline var) > 0) {
        split(var, arr, /\034/);

        print arr[2];
    }
    close(sort_exe);
}

ソートするために行数を \034 を区切りにして文字列を作成していますが、awk 自体のメモリは消費しなくなると思います。

実行してみます。

$ seq 10 | gawk -f tac2.awk
10
9
8
7
6
5
4
3
2
1

$ gawk -f tac2.awk tac2.awk
}
    close(sort_exe);
    }
        print arr[2];

        split(var, arr, /\034/);
    while ((sort_exe |& getline var) > 0) {
    ## コプロセスの出力を getline で読み取る

    close(sort_exe, "to");
    ## 入力のパイプだけを閉じる
END {

}
    printf("%d\034%s\n", NR, $0) |& sort_exe;
    ## コプロセスに渡す
{

}
    sort_exe = "sort -t \"\034\" -nr"
    ## 区切は \034 とし、他の文字との競合を避ける
BEGIN {

## tac2.awk
#! /usr/local/bin/gawk -f

このようにソートしてもテンポラリファイルに記述することなくコプロセスからの情報を得ることができます。

tag_gawk.png tag_gawk.png