2021年10月31日日曜日

POSIX sedとGNU sedの両方で動かすテクニック4種盛り

POSIX sed(macOS標準)とGNU sed(Linux標準)とで微妙に書き方が違うので、どちらでも動くようにシェルスクリプト等を書きたい場合の注意事項をちょっとまとめてみました。

縛りプレイとして、sedコマンドだけで対応するものとします。つまり、パイプやリダイレクト、他のコマンドとの併用などは行わないものとします。

以下の内容は、macOS(POSIX sed)とLinux(GNU sed)の両方で動くことを確認済みですが、どちらも割と新しいバージョンで確認したので古いバージョンでは使えない可能性もあります。ご注意ください。

拡張正規表現は-rではなく-E

GNU sedでは拡張正規表現を使う場合、GNU sedでは-rを使うと思いますが、POSIX sedでは-Eを使います。どちらでも動くようにしたい場合はどうすればいいのでしょうか。

実は、GNU sedでも拡張正規表現に-Eを使えますmanページにそのことが記載されていないのでわかりづらいのですが、使えます。

ただ、「拡張」といっても基本正規表現でできないことができるようになるわけではなく、いくつかのメタ文字がバックスラッシュによるエスケープを使わずに表記できるようになるだけなので、エスケープの手間さえ我慢できるなら基本正規表現を使う方針でもいいかもしれません。

インプレースは-i".bak"

次に困るのはファイルを上書きして中身を書き換えたい場合。

GNU sedでは-iだけでインプレースで処理できますが、POSIX sedでは-iの後に拡張子を指定する必要があります。

仕方ないのでバックアップの拡張子は甘んじて受け入れましょう-i".bak"と書けば、常にバックアップファイルはできてしまいますがどちらのsedでもインプレースで処理できます。

Gitでソースコード管理しているなら、*.bak.gitignoreに入れておけば特に気にならないと思います。

\sとかは使えないからPOSIX 文字クラスを使う

GNU sedではホワイトスペースを表すのに\sを使ったりすると思いますが、POSIX sedでは使えないのでPOSIX文字クラス[[:space:]]を使いましょう。これならGNU sedでも使えます。

改行への置換はちょっとしたトリックが必要

多分一番の難関が改行への置換。GNU sedでは\nだけで済みますが、POSIX sedではこの方法が使えません。

POSIX sedで改行を使うにはちょっとトリックが必要です。例えば文字Xを改行に置換する場合はこう。

sed "s/X/"\\$'\n'"/g"

一旦s/X/で文字列を区切って、$'\n'で改行を生成して、その後に残りの文字/gをつなげています。ただし、そのままつなげるだけだとガチで改行されてしまい、sedにはs/X/しか渡されません。そこで改行前に\\をつけることでsedには\+改行文字が渡され、なんやかんやでいい感じに改行してくれます。

同じ意味ですが、2行になってもいいなら以下のようにも書けます。

sed "s/X/"\\"
/g"

手品が趣味なのでトリック大好き。

0 件のコメント:

コメントを投稿