Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2911

AWKでprint $0 時にOFSの設定を反映する(区切り文字の指定)

$
0
0

何をしたいか

awkで、一行全体の表示print $0時に、出力ファイル区切り文字OFSを指定しても機能しない現象を何とかしたい。

状況

テーブルの区切り文字を変換して出力したい、処理結果をカンマ区切りで出力したい…等

例)こんなCSVを用意する。これをタブ区切りに変換して出力したいとする。

$ cat test.csv
a,b,c,d,e,f
1,32,6543,45,4,45
2,45,521,343,1,211
3,32,321,641,-2,377
4,45,56,939,-5,543
5,32,532,1237,-8,709
6,45,7,1535,-11,875

現象

$ gawk 'BEGIN {FS=","; OFS="\t";} {print $0}'
a,b,c,d,e,f
1,32,6543,45,4,45
2,45,521,343,1,211
3,32,321,641,-2,377
4,45,56,939,-5,543
5,32,532,1237,-8,709
6,45,7,1535,-11,875 # 区切り文字が変わっていない!

対処

$つき変数に対して何らかの適当な代入処理を行う。$1=$1;程度の簡単なものでよい。

$ gawk 'BEGIN {FS=","; OFS="\t";} {$1=$1; print $0}'
a       b       c       d       e       f
1       32      6543    45      4       45
2       45      521     343     1       211
3       32      321     641     -2      377
4       45      56      939     -5      543
5       32      532     1237    -8      709
6       45      7       1535    -11     875 # タブ区切りが反映された

原因

ここまで書いて同一内容の先行記事を見つけた。

これでは差分がないので、少し原因を調べてみることにする。

調査結果

  • フィールド$0の再構成タイミングはいつか、という問題に尽きる。

The GAWK Manual Edition 0.15より
入力ファイルの読み込み > フィールド分割の指定の節に、ほとんど回答になっている以下の記述がある。

先頭や末尾にある連続した空白をはぎとるという動作は、$0が再計算されたときには常におこなわれる。したがって、

echo '   a b c d' | awk '{ print; \$2 = $2; print }'

このパイプラインは次のような結果となる。

   a b c d
a b c d

最初のprint文は読んだままのレコードを、行頭の空白を含んだ形で出力する。 \$2に対する代入で\$0 は\$1 から\$NFまでをOFSを 区切りとして連結した結果に再構成される。

なお、慣れていない人向けに書くと、単にprintと書くのはprint $0の省略形である。

つまり、(明確に記述されているわけではないが)単純にprint $0を実行するだけでは$0は再構成されないことが推察される。再構成されない限りOFSは反映されず、元の文字列がそのまま出力されることになるというわけである。

フィールド代入の結果元のデータを変更せず、かつ$0の再構成を誘発し、最も短く書ける文が$1=$1;というわけだ。

ちなみに、$0=$0;は再構成を発生させないので、今回の問題の解決には効果がない(試されたし)。

執筆理由

久しぶりにawkを使ってトラブった。基本的な内容だが、意外に日本語記事が少なかったため。
WindowsでもWSLが使えるようになって、シェルのツールがかえって便利になってきつつあるので、こういった温故知新ツールの出番が増えるかもしれませんね。


Viewing all articles
Browse latest Browse all 2911

Trending Articles