awkでawkを書くようなワンライナーの書き方
例えば、こういう場合を考える
find . | awk '/\.sql$/{ print $0}' ./src/sql/testenv.sql ./src/sql/testtab.sql
こういうときに、カレントより下にある、拡張子がsqlなファイルを、全部.sql.bakに変えるコマンドが得たいときはこうする
find . | awk '/\.sql$/{print "mv "$0 " "$0".bak"}' mv ./src/sql/testenv.sql ./src/sql/testenv.sql.bak mv ./src/sql/testtab.sql ./src/sql/testtab.sql.bak
実行したいときは、こうやる。
find . | awk '/\.sql$/{print "mv "$0 " "$0".bak"}' | sh (何も表示されない)
後ろに、パイプでshに渡してやると、そのまま実行される。まぁ、これはよくやるのであまり悩むことは無い。
今日は、awkでawkを書こうとして悩んだ。つまりこういうとき
find . | awk '/\.sql$/{ print $0}' ./src/sql/testenv.sql ./src/sql/testtab.sql
こういう場合に、こういう出力を得たい、という場合
find . | awk '/\.sql$/{ print "cat "$0" | awk /hoge/{print \""$0"\" $0}"}' cat ./src/sql/testenv.sql | awk /hoge/{print "./src/sql/testenv.sql" $0} cat ./src/sql/testtab.sql | awk /hoge/{print "./src/sql/testtab.sql" $0}
このコマンドの出力で、シングルクォーテーションの出力方法に困った。最初、¥でエスケープすれば良いだろうと思ってこうやって失敗
find . | awk '/\.sql$/{ print "cat "$0" | awk \'/hoge/{print \""$0"\" $0}\'"}' > (コマンドが終わってない。つまりエスケープが効いていない)
さんざん悩んだ末に、ようやくたどり着いた答えはこれ
find . | awk '/\.sql$/{ printf("cat %s | awk %c/hoge/{print \"%s\" $0}%c\n",$0,39, $0,39)}' cat ./src/sql/testenv.sql | awk '/hoge/{print "./src/sql/testenv.sql" $0}' cat ./src/sql/testtab.sql | awk '/hoge/{print "./src/sql/testtab.sql" $0}'
つまり。awkの中で、シングルクォーテーションを出したい場合は、39を%cで出せば良い。
echo "" | awk '{printf("%c",39)}'
ほんとうに、3時間ぐらい悩んだ。ちなみにダブルクォーテーションは\"で出せる、紛らわしい。でもやっぱり、メタプログラミングは楽しい。