はじめに結論から書くと sed -i -r
と分けた形でオプションを指定すれば良いです。
概要
例えばaptのリポジトリを書き換える作業が必要な場合を想定します。
下記のように拡張正規表現を利用し-ir
の順番でオプションを指定した場合、
うまく書き換えることができません。
$ cat /etc/apt/sources.list | grep '^deb'|head -2
deb http://archive.ubuntu.com/ubuntu/ kinetic main restricted
deb http://archive.ubuntu.com/ubuntu/ kinetic-updates main restricted
## 「-ir」を指定して(archive|security)をold-releasesに書き換え
$ sed -ir 's@(archive|security).ubuntu.com@old-releases.ubuntu.com@g' /etc/apt/sources.list
## 書き換わってない
$ cat /etc/apt/sources.list | grep '^deb'|head -2
deb http://archive.ubuntu.com/ubuntu/ kinetic main restricted
deb http://archive.ubuntu.com/ubuntu/ kinetic-updates main restricted
しかし、なぜかオプションの順番を逆に指定すると想定通りに書き換えることができます。
## 「-ri」を指定して(archive|security)をold-releasesに書き換え
$ sed -ri 's@(archive|security).ubuntu.com@old-releases.ubuntu.com@g' /etc/apt/sources.list
## 書き換わっている
$ cat /etc/apt/sources.list | grep '^deb'|head -2
deb http://old-releases.ubuntu.com/ubuntu/ kinetic main restricted
deb http://old-releases.ubuntu.com/ubuntu/ kinetic-updates main restricted
多くのLinuxコマンドではオプションを連続して指定することができるため、
オプションの順番で振る舞いが変わることは奇妙な振る舞いに感じます。
説明とか
この現象は、sedでは-i
オプションのあとに文字が続いた場合はその文字をバックアップファイルのサフィックスとして扱うという仕様のために発生しています。
-i[SUFFIX], --in-place[=SUFFIX]
ファイルをインプレース処理で編集します (SUFFIX 指定時はバックアップを取ります)
「 Man page of SED」 より
つまりsed -ir
と指定した場合は、ファイルを上書きしてr
というバックアップファイルを作成することになります。
-i[SUFFIX]
の仕様は下記のように.bakをつけたバックアップファイルを作るために使用されることが多いです。
$ sed -i.bak 's/a/b/' test.txt
$ ls
test.txt test.txt.bak
実際にsed -ir
を使用した記事最初の例では該当ディレクトリにr
がついたバックアップファイルが作成されています。
$ ls -p /etc/apt/|grep -v /
sources.list
sources.listr
つまり-ir
のオプション指定で想定通りに書き換わらない理由は、
-r
オプションが指定されていないために拡張正規表現が利用できないことによるものです。
-ir
オプションでもうまく行く場合
レアケースかもしれませんが下記のように-ir
を指定していても拡張正規表現を利用しなければうまくいきます。
## 「-ir」を指定して(archive|security)をold-releasesに書き換え
$ sed -ir 's@archive.ubuntu.com@old-releases.ubuntu.com@;s@security.ubuntu.com@old-releases.ubuntu.com@' /etc/apt/sources.list
## 書き換わっている
$ cat /etc/apt/sources.list | grep '^deb'|head -2
deb http://old-releases.ubuntu.com/ubuntu/ kinetic main restricted
deb http://old-releases.ubuntu.com/ubuntu/ kinetic-updates main restricted
そしてr
とサフィックスについたバックアップファイルが作成されます。
結論
sed -i -r
またはsed -r -i
という個別に指定する形式でオプションを書くのが良いぽいです。
オプションの順番で躓く心配はなくなります。
備考
StackOverflowに同じことが書かれてたりします。
https://stackoverflow.com/questions/17525378/sed-command-order-of-option-flags-matters-ir-vs-ri
言語が違ってても同じミスをする人がいるのは感慨深いというかなんというか……
この記事が誰かの役に立てば幸いです。