Linux(GNU)とMac(BSD)のsedの振る舞いの違いを解決(オーバーライド版)


要旨

sedでファイルを直接書き換えようとした際に、-iのサフィックスの振る舞いが Linux(GNU) と Mac(BSD) で異なります。

GNU Style

sed -i -e 's/foo/bar/g' file.txt           # バックアップ作成されない
sed -i.bak -e 's/foo/bar/g' file.txt       # file.txt.bakが作成される

BSD Style

sed -i '' -e 's/foo/bar/g' file.txt        # バックアップ作成されない
sed -i '.bak' -e 's/foo/bar/g' file.txt    # file.txt.bakが作成される

エイリアスを使った方法は
https://qiita.com/narumi_888/items/e425f29b84da6b72ad62
で紹介されていますが、この記事は sed のまま使いたい、既存のスクリプトを書き換えたくない人向けです。

こんな人向け

  • シェルスクリプトで sed を iオプション 付きで使う
  • Linux(GNU sed)とMac(BSD sed)の開発者が混在している
  • Macの開発者にGNU sedへの入れ替えを強要するのはちょっと・・・
  • エイリアスはなんか嫌だ

解決

sedというシェル関数を定義し、正しい振る舞いに書き換えます。

function sed(){
    # sedコマンドオーバーライド
    # macOS標準の BSD sed は GNU sed の-iオプション指定方法と異なるので、GNUに合わせるようオーバーライドする

    if command sed --version 2>&1 | grep -q GNU; [ $? -ne 0 ] \
    && [ "${1:0:2}" == "-i" ]
    then
        # BSD sed かつ -iオプション有り
        # -iオプションの拡張子を書き換える
        BACKUP_EXT=${1:2}
        shift
        command sed -i "$BACKUP_EXT" "$@"
        return $?
    else
        # sedコマンドそのまま実行
        command sed "$@"
        return $?
    fi
}