Moving back to Bash
Back in macOS Catalina, Apple changed the default shell from bash to zsh. For years I continued to just use zsh as I saw no real difference, however recently I've decided to move back to bash after watching a lot of Dave Eddy's videos. I think I sold it to myself as a good idea, mainly because my servers use bash by default, and most of my script have the shebang #!/usr/bin/env bash not #!/usr/bin/env zsh. That's not to say that I did not try to dabble with zsh. But coming from Linux, I's always end up falling back to bash, so why not switch my shell.
Bash versions
The default bash version shipped with macOS is super old.
/bin/bash --version
GNU bash, version 3.2.57(1)-release (arm64-apple-darwin25) Copyright (C) 2007 Free Software Foundation, Inc.
Whereas, the bash from brew is much newer.
/opt/homebrew/bin/bash --version
GNU bash, version 5.3.3(1)-release (aarch64-apple-darwin25.0.0) Copyright (C) 2025 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
This means, when using chsh to change the shell, I want to use the one from Homebrew, and not the one shipped with macOS.
Setup
- add
/opt/homebrew/bin/bashto/etc/shells - run
chsh -s /opt/homebrew/bin/bash - add
eval "$(/opt/homebrew/bin/brew shellenv)"in~/.bash_profile - add this to
~/.bash_profiletoo
if [ -f ~/.bashrc ]; then source ~/.bashrc fi
The only thing now, is to setup your ~/.bashrc the way you want it. and then confirm its all as expected.
echo $SHELL && echo $BASH_VERSION
/opt/homebrew/bin/bash 5.3.3(1)-release
My prompt
The look and feel of my PS1 is really important to me, in zsh I had it the way I liked. After a Sunday afternoon, my bash prompt code now looks like this, which emulates what I had in zsh.
if [ -f "${HOME}/.abbr_pwd.bash" ]; then source "${HOME}/.abbr_pwd.bash" FG_RED='\[\e[31m\]' FG_GREEN='\[\e[32m\]' FG_WHITE='\[\e[37m\]' FG_RESET='\[\e[0m\]' git_info() { local dir="$PWD" while [ "$dir" != "/" ]; do if [ -d "$dir/.git" ]; then if branch=$(git -C "$dir" symbolic-ref -q --short HEAD 2>/dev/null); then echo "$branch" elif tag=$(git -C "$dir" describe --tags --exact-match --abbrev=0 HEAD 2>/dev/null); then echo "$tag" else git -C "$dir" rev-parse --short HEAD fi return fi dir="$(dirname "$dir")" done } set_prompt() { local last_exit=$? local exit_status_display="" if [ $last_exit -ne 0 ]; then exit_status_display="${FG_RED}(${last_exit})${FG_RESET}" fi local abbr_path="$(pwd_abbr)" local venv="" local venv_display="" if [ -n "$VIRTUAL_ENV" ]; then venv="$(basename "$VIRTUAL_ENV")" venv_display="${FG_GREEN}${venv}${FG_RESET}" export PATH="$VIRTUAL_ENV/bin:$PATH" fi local git="" local git_display="" git="$(git_info)" if [ -n "$git" ]; then git_display="${FG_GREEN}${git}${FG_RESET}" fi local middle="" if [ -n "$venv_display" ]; then middle+=" ${venv_display}" fi if [ -n "$git_display" ]; then middle+=" ${git_display}" fi export PS1="${FG_WHITE}[${abbr_path}${middle}${FG_WHITE}]${exit_status_display}\\$ ${FG_RESET}" } PROMPT_COMMAND="set_prompt" else export PS1='\u@\h:\w\$ ' fi
Where .abbr_pwd.bash looks like this;
pwd_abbr() { local path="${PWD}" local home="${HOME}" if [[ "$path" == "$home"* ]]; then path="~${path#$home}" fi IFS='/' read -r -a parts <<< "$path" local result="" local i local len=${#parts[@]} for (( i=0; i<$len; i++ )); do local part="${parts[i]}" if [[ "$part" == "~" ]]; then result="~" elif (( i == len - 1 )); then result+="/$part" elif [[ -n "$part" ]]; then result+="/${part:0:1}" fi done echo "$result" }
Now I get a nice looking prompt :)