sed -i works differently on GNU sed (Linux) and BSD sed (macOS). GNU accepts sed -i 's/...//' file. BSD requires sed -i '' 's/...//' file with an explicit empty backup extension. Forgetting this turns your Makefile into a landmine for whoever checks it out next.

The portable trick is to always pass a backup extension and then remove the backup afterwards. It looks verbose but it works identically on both.

# Portable: works on GNU and BSD sed.
sed -i.bak 's/old/new/g' file.txt && rm -f file.txt.bak

For multiple files, loop or use find -exec:

find . -name '*.go' -type f -exec sed -i.bak 's/\bfoo\b/bar/g' {} + \
  && find . -name '*.bak' -delete

If you have a team that runs both macOS and Linux, wrap it in a tiny function:

sedi() {
    if sed --version >/dev/null 2>&1; then
        sed -i "$@"         # GNU
    else
        sed -i '' "$@"      # BSD
    fi
}

Caveats: sed -i with word boundaries (\b) works on GNU but not on default BSD. On macOS, install gsed via Homebrew if you want the full GNU feature set in scripts. See also /snippets/find-modified-today-multi-repo/.