sed で変数を使った置換ができないときの解決方法~シェル展開の落とし穴とダブルクォート・エスケープの正しい使い方~

  • URLをコピーしました!

s コマンドで文字列を置換するとき、「シェル変数を使いたいのに効かない」というトラブルは非常によくあります。

例えば次のようなケースです。

pattern="foo"
replacement="bar"

echo "foo test" | sed 's/$pattern/$replacement/'

期待通りなら "bar test" になるはずですが、実際は置換されず "foo test" のまま。
なぜでしょうか?

目次

1. 原因は「シェル展開されていない」こと

シングルクォート ' ' で囲むと、その中の文字は シェルによる変数展開が行われません
したがって、上記の $pattern$replacement文字列としてそのまま sed に渡されてしまいます。

2. 解決方法:ダブルクォートを使う

変数を展開させたい場合は、ダブルクォート " を使います。

echo "foo test" | sed "s/$pattern/$replacement/"

→ 出力:

bar test

これで期待通り、foobar に置換されました。

3. ただし「特殊文字」に注意!

もし変数に /&\ など sed の特殊文字 が含まれている場合、そのままでは思わぬ挙動をします。

例: / を含む場合

replacement="a/b"
echo "foo" | sed "s/foo/$replacement/"

エラーになる、もしくは意図通り動かないことがあります。

4. 対策:区切り文字の変更とエスケープ

区切り文字を / 以外にする

s/// の区切り文字は / 以外でもOK。たとえば # を使うと安全です。

replacement="a/b"
echo "foo" | sed "s#foo#$replacement#"

→ 出力:

a/b

&\ を含む場合

  • & は「マッチした文字列」を意味するので、リテラルとして使うにはエスケープが必要です。
  • バックスラッシュ \ は二重解釈されやすいので、\\\ にしておくと安心です。

5. まとめ

  • シングルクォート ' ' では変数は展開されない
  • 変数を使いたいときはダブルクォート " " を使う
  • / を含むなら区切り文字を変える(#| など)
  • &\ はエスケープが必要
編集後記

私も昔、設定ファイルの置換をシェルスクリプトで書いていて「変数が展開されない!sedが壊れてるのか?」と数時間悩みました…。
原因は単純で「シングルクォートで囲んでいた」だけ。クォートの違いを理解してからは一気にトラブルが減りました。

よくあるエラーと解決方法まとめ
目次