結論
発端
例えば以下のようなテキストファイルがあったとして、
~ $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コマンドで確実に使える正規表現は以下のみ(正確にはPOSIX 1003.2で規定されているsed)
- .
- *
- ^
- $
- \(regexp\)
- \1 \2 \3 \4 \5 \6 \7 \8 \9
- [char-list]
- \{n,m\}
- \{n,\}
- \{n\}
- [:alnum:]
- [:alpha:]
- [:blank:]
- [:cntrl:]
- [:digit:]
- [:graph:]
- [:lower:]
- [:print:]
- [:punct:]
- [:space:]
- [:upper:]
- [:xdigit:]
で、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
えへへ