sedで置換がうまくいかなかった話

はじめに

本記事は、Qiitaに投稿した記事を移行したものです。

ファイル内の特定の文字列をsedで置換しようとしたときにうまくいかなかったので解決法を書いておきます。

環境

$ uname -a
Linux tk2-227-23187 3.13.0-98-generic #145-Ubuntu SMP Sat Oct 8 20:13:07 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

$ bash --version
GNU bash, バージョン 4.3.11(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

問題1

HOGE="hoge"
FUGA="fuga"
sed -e s/$HOGE/$FUGA/g file.txt > file.txt

ファイルが空っぽに...
いったん別ファイルに出力して、リネームすることで解決
@hmikisatoさんに-iオプションを教えていただいたので、-iオプションを使うように変更しました。

sed -i -e s/$HOGE/$FUGA/g file.txt

>によるリダイレクトは、実行した時点でリダイレクト先のファイルを空にして開きます。
そのため実行開始時点でfile.txtは空になり、空のファイルを対象にsedを実行しても実行結果は空です。
環境はUbuntuとのことでsedGNU版のものと仮定しますが、この場合は -i オプションを利用することで元ファイルの上書きが可能です。

問題2

sed: -e expression #1, char 10: `s' に対するオプションが不明です

何かエラー出た...

こんなことしようとしたらエラーが出ました。

HTTP="http://example.com"
HTTPS="https://secure.example.com"

sed -e s/$HTTP/$HTTPS/g file.txt > file.tmp
mv file.tmp file.txt

変数に代入した/(スラッシュ)が原因のようです。
こう書きなおしました。

URL_A="example.com"
URL_B="secure.example.com"
HTTP="http"
HTTPS="https"

sed -e s/$HTTP/$HTTPS/g file.txt > file.tmp
mv file.tmp file.txt

sed -e s/$URL_A/$URL_B/g file.txt > file.tmp
mv file.tmp file.txt

こちらも@hmikisatoさんに教えていただいた通りに変更しました。

sedのsコマンドは、sの次に書いた文字を置換元文字列と置換先文字列の区切りとして認識します。
そのため例えば

$ sed -i -e s:$HTTP:$HTTPS:g file.txt

といったことが可能です。

URLには:(コロン)が含まれていたので、私は、*(アスタリスク)を使いました。
最終的に、こんな感じになりました。

HTTP="http://example.com"
HTTPS="https://secure.example.com"

sed -i -e s*$HTTP*$HTTPS*g file.txt

@hmikisatoさん、コメントしていただき、ありがとうございました。