sedで複数行にまたがった文字列を置換する方法

2020-01-21Bash

はじめに

sed コマンドで置換を行う場合、 複数行にまたがった文字列も置換対象としたい場合があります。

検証環境

$ uname -moi
x86_64 MacBookPro11,4 Darwin

$ bash -version | head -n 1
GNU bash, バージョン 5.0.11(1)-release (x86_64-apple-darwin18.6.0)

$ sed --version | head -n 1
sed (GNU sed) 4.2.2

置換対象の文字列が複数行にまたがる場合とは?

sed はラインエディタの思想を受け継いでいるため、 基本的に入力情報を1行ずつ受け取って処理を行 います。

例えば、 % で囲まれた部分を空文字に置換するといった場合、合致パターンが1行で収まるため容易に置換できます。

$ echo 'xx%aaa%yyy'
xx%aaa%yyy

$ echo 'xx%aaa%yyy' | sed 's/%.*%//'
xxyyy

ところが、 合致パターンが複数行にまたがったときにはうまく置換してくれません。

$ echo 'xxx%aaa
bbb%yyy'
xxx%aaa
bbb%yyy

# 置換されない
$ echo 'xxx%aaa
bbb%yyy' | sed 's/%.*%//'
xxx%aaa
bbb%yyy

コマンドラインオプションを追加することで、簡単に対処することができます。

置換対象の文字列が複数行にまたがる場合は -z オプションを使う

sed-z オプションを利用します。
これは sed のデフォルトの挙動である「行単位の処理」から「ヌル文字単位の処理」に挙動を切り替える、というオプションになります。

注意しなければならないのは、GNU版のsedでしか利用できないオプションである点です。Linuxの場合はGNU版のsedが導入されているディストリビューションが多いですが、Macの場合にはGNU版のsedを brew install しましょう。

通常のテキストにヌル文字が入っていることはありませんので、これによりテキスト全体を読み込み、一度に置換するようになります。

$ echo 'xxx%aaa
bbb%yyy' | sed -z 's/%.*%//'
xxxyyy

ひとこと

注意しないといけない点があります。
通常は行単位に実行される sed を全文字列を一度に処理することになるため、メモリ負荷が増えます。

あまりに巨大なファイルを処理する場合にはメモリ不足の注意が必要です。

2020-01-21Bash