動かざることバグの如し

近づきたいよ 君の理想に

sedコマンドで正規表現を使う場合は注意が必要

結論

発端

例えば以下のようなテキストファイルがあったとして、

~ $cat /tmp/sample.txt
1a
2b
3c
4a
5b

「a」を含む行を一括削除したいとする。以下のコマンドで可能

~ $sed -e '/a/d' /tmp/sample.txt
2b
3c
5b
  • -e のあとに条件式を書く(省略した場合は第一引数が条件になる)
  • /dは置き換えではなく削除の意味

仕様が変わって、「a」に加えて「b」を含む行も削除したいとする。

するとこうなる。

~ $sed -e '/a/d' /tmp/sample.txt | sed -e '/b/d'
3c

sedコマンドの仕様上、-e を連続して書けば複数条件式を指定できるので、以下のほうが好ましい

sed -e '/a/d' -e '/b/d' /tmp/sample.txt
3c

例なので単純だが、複雑な条件式だった場合正規表現で記述したほうがシンプルな例もあると思う

sed -E '/[a|b]/d' /tmp/sample.txt

だがこのコマンドは動くsedとエラーになるsedがある

どういうこと?

そもそもsedコマンドで確実に使える正規表現は以下のみ(正確にはPOSIX 1003.2で規定されているsed)

で、GNU sedでは↑に加えて以下も利用可能 つまり拡張版ってわけ

拡張対応済み(GNU sed)のバージョンなら動くが、バージョンやビルドオプション等によって動いたり動かなかったりする(実際同じOS,sedコマンドのバージョンでも挙動が違った)

さっきの sed -E '/[a|b]/d' /tmp/sample.txt は拡張側に含まれる正規表現パターンだったのでNGだったわけ

対策

対策1

正規表現を使わないで愚直にいく

対策2

POSIX 1003.2で規定されているsed正規表現パターンのみ使う

のでさっきの例だと

~ $sed -E '/(a|b)/d' /tmp/sample.txt
3c

になる (カッコが[]から()へ変更)

なんかgrepコマンドでも同じ状況にハマった気がするけど、気をつけよう。。。

対策3

自分でsedコマンドをビルドしてmake install

えへへ

参考リンク