LoginSignup
0
0

More than 1 year has passed since last update.

sedでオプションの順番は(-ri)が正解で(-ir)はNG

Posted at

はじめに結論から書くと 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
言語が違ってても同じミスをする人がいるのは感慨深いというかなんというか……

この記事が誰かの役に立てば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0