Skip to content

Instantly share code, notes, and snippets.

@jamestomasino
Created May 1, 2026 15:15
Show Gist options
  • Select an option

  • Save jamestomasino/3bdfaacb80c4bd4f1f6e06629ec66ba9 to your computer and use it in GitHub Desktop.

Select an option

Save jamestomasino/3bdfaacb80c4bd4f1f6e06629ec66ba9 to your computer and use it in GitHub Desktop.
Make macOS shell run in parity with Linux
#!/usr/bin/env bash
set -euo pipefail
log() {
printf '\n[%s] %s\n' "$(date '+%H:%M:%S')" "$*"
}
append_if_missing() {
local file="$1"
local line="$2"
touch "$file"
if ! grep -Fqx "$line" "$file"; then
printf '%s\n' "$line" >> "$file"
fi
}
detect_brew_prefix() {
if [[ -x /opt/homebrew/bin/brew ]]; then
echo "/opt/homebrew"
elif [[ -x /usr/local/bin/brew ]]; then
echo "/usr/local"
else
echo ""
fi
}
ensure_homebrew() {
if ! command -v brew >/dev/null 2>&1; then
echo "Homebrew is required but not installed."
echo "Install it first from https://brew.sh and re-run this script."
exit 1
fi
}
main() {
ensure_homebrew
local brew_bin
brew_bin="$(command -v brew)"
local brew_prefix
brew_prefix="$(brew --prefix)"
log "Updating Homebrew"
brew update
log "Installing Linux-parity CLI packages"
brew install \
bash \
coreutils \
findutils \
gawk \
gnu-getopt \
gnu-sed \
gnu-tar \
grep \
make \
diffutils \
less \
ed \
watch \
jq
log "Upgrading existing formulae"
brew upgrade
log "Ensuring modern Bash is listed in /etc/shells"
local bash_path
bash_path="$(brew --prefix)/bin/bash"
if ! grep -Fxq "$bash_path" /etc/shells 2>/dev/null; then
echo "Adding $bash_path to /etc/shells, sudo may prompt once."
printf '%s\n' "$bash_path" | sudo tee -a /etc/shells >/dev/null
fi
if [[ "${SHELL:-}" != "$bash_path" ]]; then
log "Switching default shell to Homebrew Bash"
chsh -s "$bash_path" || true
fi
log "Configuring shell startup files"
local zprofile="$HOME/.zprofile"
local zshrc="$HOME/.zshrc"
local bash_profile="$HOME/.bash_profile"
local bashrc="$HOME/.bashrc"
append_if_missing "$zprofile" 'eval "$(/opt/homebrew/bin/brew shellenv 2>/dev/null || /usr/local/bin/brew shellenv)"'
append_if_missing "$bash_profile" '[[ -f ~/.bashrc ]] && source ~/.bashrc'
local parity_block_start="# >>> linux-parity-bootstrap >>>"
local parity_block_end="# <<< linux-parity-bootstrap <<<"
local parity_block
parity_block=$(cat <<'EOF'
# >>> linux-parity-bootstrap >>>
export HOMEBREW_NO_AUTO_UPDATE=1
if command -v brew >/dev/null 2>&1; then
eval "$(brew shellenv)"
PATH="$(brew --prefix coreutils)/libexec/gnubin:$PATH"
PATH="$(brew --prefix findutils)/libexec/gnubin:$PATH"
PATH="$(brew --prefix gnu-sed)/libexec/gnubin:$PATH"
PATH="$(brew --prefix gawk)/libexec/gnubin:$PATH"
PATH="$(brew --prefix grep)/libexec/gnubin:$PATH"
PATH="$(brew --prefix make)/libexec/gnubin:$PATH"
PATH="$(brew --prefix gnu-tar)/libexec/gnubin:$PATH"
PATH="$(brew --prefix gnu-getopt)/bin:$PATH"
MANPATH="$(brew --prefix coreutils)/libexec/gnuman:${MANPATH:-}"
MANPATH="$(brew --prefix findutils)/libexec/gnuman:${MANPATH:-}"
MANPATH="$(brew --prefix gnu-sed)/libexec/gnuman:${MANPATH:-}"
MANPATH="$(brew --prefix gawk)/libexec/gnuman:${MANPATH:-}"
MANPATH="$(brew --prefix grep)/libexec/gnuman:${MANPATH:-}"
MANPATH="$(brew --prefix make)/libexec/gnuman:${MANPATH:-}"
MANPATH="$(brew --prefix gnu-tar)/libexec/gnuman:${MANPATH:-}"
fi
export NVM_DIR="$HOME/.nvm"
if [[ -s "$(brew --prefix nvm 2>/dev/null)/nvm.sh" ]]; then
. "$(brew --prefix nvm)/nvm.sh"
elif [[ -s "$NVM_DIR/nvm.sh" ]]; then
. "$NVM_DIR/nvm.sh"
fi
# <<< linux-parity-bootstrap <<<
EOF
)
for rc in "$zshrc" "$bashrc"; do
touch "$rc"
if ! grep -Fq "$parity_block_start" "$rc"; then
printf '\n%s\n' "$parity_block" >> "$rc"
fi
done
log "Running brew cleanup"
brew cleanup
log "Basic verification"
echo "brew: $(brew --version | head -n 1)"
echo "bash: $("$bash_path" --version | head -n 1)"
echo "sed: $(sed --version 2>/dev/null | head -n 1 || true)"
echo "awk: $(awk --version 2>/dev/null | head -n 1 || true)"
echo "make: $(make --version | head -n 1)"
echo "tar: $(tar --version | head -n 1)"
echo "find: $(find --version 2>/dev/null | head -n 1 || true)"
cat <<EOF
Done.
Next steps:
1. Open a new terminal session.
2. Verify:
which bash sed awk make tar find
3. Expected:
bash -> $brew_prefix/bin/bash
sed/awk/make/tar/find should resolve to Homebrew GNU versions first.
Note:
- BSD and Apple tools still exist on the system.
- This script makes GNU tools win via PATH, which is the safest parity model.
- If your repos hardcode /bin/bash, update those shebangs to /usr/bin/env bash.
EOF
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment