スクリプトを書いていて,コマンドの引数やら,awkのスクリプトやらにシェルの変数を用いることはほんっとーによくあることだと思います.まず先に結論をいうと,
"変数展開に気をつけろ"
ということです.
この先を見てもらえれば当たり前の話じゃねーかよって感じで恐縮ですが,なんどもこいつでつまずいてるので,自分を戒めるためにメモ.
自分がはまっていた具体例をまず出します.awkの正規表現中にシェルの変数を用いる,というものです.これはawkスクリプトを「'」か「"」のいずれかで囲った場合に分けて,次のように記述できます.
ptn="foo"
echo "foo bar" | awk '/'${ptn}'/{print $0}'
#または
echo "foo bar" | awk '/'''${ptn}'''/{print $0}'
ptn="foo"
echo "foo bar" | awk "/${ptn}/{print \$0}"
#または
echo "foo bar" | awk "/"""${ptn}"""/{print \$0}"
トリプルクォートは調べてたら見つかったのでおまけです(用途がいまいちピンとこないので教えていただければ喜びます).けれどもこやつら,完璧ではありません.この渡し方では上記の変数hogeに空白が含まれている場合,構文エラーとなってしまいます.なので,以下のように記述すれば空白を含む変数に対しても有効となります.
ptn="foo bar"
# OK
echo "hoge foo bar" | awk '/'"${ptn}"'/{print $0}'
# ERROR
echo "hoge foo bar" | awk '/'${ptn}'/{print $0}'
じゃあ先の記述だとなにがいけないのか.肝となるのはシェルの変数展開です.変数を「"」でくくるか否かで,評価が変わります.
hoge="hoge foo bar"
${hoge} -> "hoge" "foo" "bar"
"${hoge}" -> "hoge foo bar"
変数には1つの文字列が格納されているにも関わらず,展開すると空白を区切り文字として複数の文字列に置き換わってしまいます.例えばこれをtouchコマンドの引数にとれば,前者ではhoge,foo,barの3つのファイルができ,後者では"hoge foo bar"という1つのファイルが出来るというわけです.
つまり先のawkの例では以下のように評価されます.
ptn="foo bar"
# OK
awk '/'"${ptn}"'/{print $0}' -> awk '/foo bar/{print $0}'
# ERROR
awk '/'${ptn}'/{print $0}' -> awk '/foo' 'bar/{print $0}'
こういうわけで,”変数展開には気をつけろ”です.以上,当たり前な話でした.