Portable sed -i across GNU and BSD
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/.