sed コマンドの用法

  • 33
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

BSD sed などに代表される POSIX に準拠した sed は OS X などで標準で使用されているが、一般的な Linux で用いられる sed は後述する GNU sed であることが多い。ゆえに、Linux ユーザが OS X の sed を使用するとオプションなどのいわゆる「方言」的な違いに混乱することでしょう。

GNU sed

GNU sed は POSIX に準拠したそれの後発であるため、拡張的機能が盛り込まれている。例えば、-i オプション。このオプションは入力ファイルの上書き保存ができるようになるオプションである。このオプションを用いずに、「sed で上書き保存をする」を実行しようとすると以下の様なケースが考えられる。

  1. $ sed 's/aaa/bbb/' input.file > input.file

    このケースはリダイレクトを用いて、sed の入力ファイルでの変更をそのまま、その入力ファイルに流そうと試みたもの。しかし、これは失敗する。試してみるとわかるが、これはリダイレクトの仕様から不可能なのである(input.file という空ファイルが出来るだけ)。

  2. $ sed 's/aaa/bbb/' input.file > output.file; mv -f output.file input.file

    このケースは、上の例の改善版。リダイレクト出来ないなら、一旦外部ファイルに落としてから、入力ファイル名にリネームしようとするもの。これは、成功する。しかし、ワンライナーがとても長くなり見づらい上に外部ファイルが生成されるというあまりスマートな解法にはならない。

ここで登場するのが -i オプションで、実際にやってみるとわかるが、

$ sed -i -e 's/aaa/bbb/' input.file

これだけでよい。これで aaa が bbb に置換された後、変更が入力ファイルに保存される。また、バックアップ用途にも使用できて、-i オプションに文字列の引数を渡してやることで、それをプレフィックスにしてバックアップ用ファイルを作成してくれる。

    $ ls
    testfile
    $ sed -i'.bak' 's/aaa/bbb/' testfile
    $ ls
    testfile    testfile.bak

ここで、-i オプションのプレフィックスについてなんですが、

  • sed -i".bak" 's/aaa/bbb/' testfile ダブルクオートでも、
  • sed -i.bak 's/aaa/bbb/' testfile 括りがなくても、
  • sed -i '.bak' 's/aaa/bbb/' testfile オプションとその引数の間にスペースがあっても

正常に動作します(環境やバージョンによっては不可能かも。)

GNU sed ない場合

インストールすれば良い。

コマンドラインから brew install gnu-sed でおしまい。インストール後にも表示されるが、GNU sed を呼び出す場合、g がプレフィックスになるので gsed で呼び出す。

GNU_sed
$ gsed --help
Usage: gsed [OPTION]... {script-only-if-no-other-script} [input-file]...

    ...


  -i[SUFFIX], --in-place[=SUFFIX]
                 edit files in place (makes backup if SUFFIX supplied)

    ...

GNU sed home page: <http://www.gnu.org/software/sed/>.
General help using GNU software: <http://www.gnu.org/gethelp/>.
exit 4

Homebrew で入れました。Homebrew のインストールなどについてはこちらから。

POSIX sed

打って変わって、POSIX sed (BSD やOS X に含まれる sed など)は、この -i オプションを用いることは出来ない。また、インストールできるような自由な環境とも限らない。その場合は、古典的ではあるがこのように、、、

1.
    $ cat testfile | (rm testfile; sed 's/aaa/bbb/' > testfile)

また -i にもあったバックアップ用途での sed 利用を POSIX sed でやる場合は以下。

2.
     cat testfile | (mv testfile testfile.bak; sed 's/aaa/bbb/' > testfile)

cat を使わずに入力リダイレクトを使用した場合は以下。

3.
     (rm testfile; sed 's/aaa/bbb/' > testfile) < testfile

3番の方法だと環境によっては bash: testfile: Permission denied と怒られる場合もあるみたい。

参考資料

http://shunirr.hatenablog.jp/entry/2012/12/19/160544
http://www.dab.hi-ho.ne.jp/sasa/biboroku/unix/sed-i.html
http://shobon.hatenablog.com/entry/2012/02/19/154018
http://www.l2tp.org/?p=5128