awkで$0出力するときにOFS指定が無視られる問題

awkでOFS指定しても出力のセパレータが無視される時がある問題がやっと解決しました.

やりたいこと

  • 何らかのセパレータで区切られたcsvファイルの中から,特定の条件を満たす行を,セパレータを変えて出力する

まぁ,こう言われればみんなawkでやろうとしますよね?そうでもない?

例えば以下のようなカンマ区切りのcsvファイル

a,b
d,c
a,e
e,d

この中から,一つ目のフィールドが"a"の行のみ,セパレータをカンマからプラスに変えて出力したいとします.
つまり,

a+b
a+e

が望む形.

この時,とりあえず思いつくのは,

% awk -F "," 'BEGIN{OFS="+"}{ if($1=="a"){print $0}}' test.csv

ですよね.OFSは出力セパレータ.始めに出力セパレータにプラスを指定しておいて,$0で全フィールド出力.

ところが,これだとうまくいきません.結果はこうなります.

a,b
a,e

ちゃんと条件は取れているのですが,セパレータが変更されていません.ですが,実は以下のように書くと意図した通りに動きます.

% awk -F "," 'BEGIN{OFS="+"}{ if($1=="a"){print $1,$2}}' test.csv

結果が以下です

a+b
a+e

何故$0(全出力)ではうまくいかず,$1,$2と全部指定するとうまくいくのかずっと謎でした.この例ではフィールドが二つだからいいですが,多くなってくると,さらにフィールドの数が可変になってくると,for文を使って全フィールド出力することになり,たったこれだけの処理なのにやけにコマンドが汚くなります.

実は理由は今でも謎ですが,以下のようにするとうまくいくことが分かりました.

% awk -F "," 'BEGIN{OFS="+"}{$1=$1; if($1=="a"){print $0}}' test.csv

結果が以下です

a+b
a+e

上記のように,$1=$1というおまじないを入れることでうまくいくようになります.

理由はかなり謎ですが,どうやら$1=$1とすることでカラムの再構成が行われてどうとか・・・?
どちらにせよ,$0で指定する場合と$1,$2...$NFで指定する場合で結果が違うというのは何か気持ち悪いです.