Throughout the years, I've been using zsh as my shell of choice. It's been a great experience and I've learned a lot about how to configure it to my liking. Here's my current zshrc file for 2024.

I've commented each thing in the .zshrc config. Some of the more personal information, but you can use this as a template for your own zshrc file.

Place this in your ~/.zshrc file and you should be good to go.

Screenshot

# Theme ZSH_THEME="sorin" # History SAVEHIST=5000 HISTFILE=~/.zsh_history # Path to your oh-my-zsh installation. export ZSH=/Users/marko/.oh-my-zsh # Banner python3 ~/Git/zshrc/banner.py # https://github.com/lincheney/fzf-tab-completion source ~/Git/fzf-tab-completion/zsh/fzf-zsh-completion.sh bindkey '^I' fzf_completion # Load Shell source $ZSH/oh-my-zsh.sh source <(fzf --zsh) # Uncomment the following line to change how often to auto-update (in days). export UPDATE_ZSH_DAYS=10 # Uncomment the following line to display red dots whilst waiting for completion. COMPLETION_WAITING_DOTS="true" # Uncomment the following line if you want to disable marking untracked files # under VCS as dirty. This makes repository status check for large repositories # much, much faster. DISABLE_UNTRACKED_FILES_DIRTY="true" # Uncomment the following line if you want to change the command execution time # stamp shown in the history command output. # The optional three formats: "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" # HIST_STAMPS="mm/dd/yyyy" # Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*) # # Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/ # Example format: plugins=(rails git textmate ruby lighthouse) # Add wisely, as too many plugins slow down shell startup. export NVM_LAZY_LOAD=true export NVM_COMPLETION=true # plugins=(nvm extract z zsh-syntax-highlighting zsh-autosuggestions) plugins=(nvm z zsh-syntax-highlighting) # User configuration export PATH="/opt/homebrew/bin/psql:/bin:/sbin:/usr/bin:/opt/homebrew/sbin:/opt/homebrew/bin:/Users/marko/pear/bin:/opt/homebrew/share/npm/bin" # PIP export PIP_REQUIRE_VIRTUALENV=false # Path Updates export PATH="/opt/homebrew/bin:$PATH" export PATH="$HOME/.node/bin:$PATH" export PATH="/opt/homebrew/opt/ruby/bin:$PATH" export PATH="/opt/homebrew/opt/php@8.0/sbin:$PATH" export PATH="/opt/homebrew/opt/php@8.0/bin:$PATH" export MYVIMRC="vimrc" # export PATH_TO_CKPT="~/Git/stable-diffusion/downloads/" export FZF_CTRL_T_OPTS="--height 60% \ --border sharp \ --layout reverse \ --prompt '∷ ' \ --pointer ▶ \ --marker ⇒" export FZF_CTRL_R_OPTS=" --preview 'echo {}' --preview-window up:3:hidden:wrap --bind 'ctrl-/:toggle-preview' --bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort' --color header:italic --header 'Press CTRL-Y to copy command into clipboard'" # tomasr/molokai export FZF_DEFAULT_OPTS='--color=bg+:#293739,bg:#1B1D1E,border:#808080,spinner:#E6DB74,hl:#7E8E91,fg:#F8F8F2,header:#7E8E91,info:#A6E22E,pointer:#A6E22E,marker:#F92672,fg+:#F8F8F2,prompt:#F92672,hl+:#F92672' # https://vitormv.github.io/fzf-themes#eyJib3JkZXJTdHlsZSI6InJvdW5kZWQiLCJib3JkZXJMYWJlbCI6IiIsImJvcmRlckxhYmVsUG9zaXRpb24iOjAsInByZXZpZXdCb3JkZXJTdHlsZSI6InJvdW5kZWQiLCJwYWRkaW5nIjoiMCIsIm1hcmdpbiI6IjAiLCJwcm9tcHQiOiI+ICIsIm1hcmtlciI6Ij4iLCJwb2ludGVyIjoi4peGIiwic2VwYXJhdG9yIjoi4pSAIiwic2Nyb2xsYmFyIjoi4pSCIiwibGF5b3V0IjoiZGVmYXVsdCIsImluZm8iOiJkZWZhdWx0IiwiY29sb3JzIjoiZmcrOiNkMGQwZDAsYmcrOiMwNDA0MDQsaGw6IzVmODdhZixobCs6IzVmZDdmZixpbmZvOiNhZmFmODcsbWFya2VyOiNkNzAwNWYscHJvbXB0OiM4N2ZmMDAsc3Bpbm5lcjojZDcwMDVmLHBvaW50ZXI6I2Q3MDA1ZixoZWFkZXI6Izg3YWZhZixib3JkZXI6IzI2MjYyNixsYWJlbDojYWVhZWFlLHF1ZXJ5OiNkOWQ5ZDkifQ== export FZF_DEFAULT_OPTS=$FZF_DEFAULT_OPTS' --color=fg:-1,fg+:#d0d0d0,bg:-1,bg+:#040404 --color=hl:#5f87af,hl+:#5fd7ff,info:#afaf87,marker:#d7005f --color=prompt:#87ff00,spinner:#d7005f,pointer:#d7005f,header:#87afaf --color=border:#262626,label:#aeaeae,query:#d9d9d9 --border="rounded" --border-label="" --preview-window="border-rounded" --prompt="> " --marker=">" --pointer="◆" --separator="─" --scrollbar="│"' # You may need to manually set your language environment # export LANG=en_US.UTF-8 # Load NVM export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion export EDITOR="vim" export VISUAL="vim" # Z (Tracks most-used directories to make cd smarter) . /opt/homebrew/etc/profile.d/z.sh # Reload alias reload="source ~/.zshrc" # Alias for ddgr alias ddg="ddgr" # Alias for dig alias dy="dig +short @dns.toys" # change to root alias ~="cd ~" # clear alias c='clear' # edit php.ini alias phpini='sudo vim /opt/homebrew/etc/php/8.0/php.ini' # edit httpd.conf # alias apacheconf='sudo vim /etc/apache2/httpd.conf' alias apacheconf='sudo vim /opt/homebrew/etc/httpd/httpd.conf' # edit new httpd.conf alias apachconfnew='sudo vim /opt/homebrew/etc/httpd/httpd.conf' # edit hosts alias hosts='sudo vim /etc/hosts' # edit this file alias editzsh='sudo vim ~/.zshrc' # edit user.conf alias userconf='sudo vim /etc/apache2/users/marko.conf' # edit httpd-vhosts.conf alias vhosts='sudo vim /opt/homebrew/etc/httpd/extra/httpd-vhosts.conf' # apache logs alias apachelogs="less +F /var/log/apache2/error_log" # colored search in files alias grep='grep --color=auto' # keys alias keys='pbcopy < ~/.ssh/id_rsa.pub' # flush dns alias flush='sudo ifconfig en0 down && sudo ifconfig en1 down && sudo ifconfig en2 down && sudo route flush && sudo ifconfig en0 up && sudo ifconfig en1 up && sudo ifconfig en2 up' # edit zshell alias zshrc='editzsh' # find todos alias todos='ack -n -R --nogroup "(TODO|FIND|FIX(ME)?):" --ignore-dir={composer,vendor,vendors,min,lib}' # find by name alias qfind="find . -name " # mute alias stfu='osascript -e "set volume output muted true"' # copy pwd alias cpwd='pwd|tr -d "\n"|pbcopy' # alias cl='fc -e -|pbcopy' # remove .git alias ungit='find . -name '.git' -exec rm -rf {} \;' # IP info alias ip='curl https://ipinfo.io/plain; echo' # alias scrapeip='curl https://icanhazip.com; echo' # myip() { # ip addr | awk '/inet / {sub(/\/.*/, "", $2); print $2}' # } # alias ip="ifconfig -a | perl -nle'/(\d+\.\d+\.\d+\.\d+)/ && print $1'" # computer power options alias reboot='sudo /sbin/reboot' alias shutdown='sudo /sbin/shutdown' alias lock='/System/Library/CoreServices/"Menu Extras"/User.menu/Contents/Resources/CGSession -suspend' alias poweroff='sudo /sbin/poweroff' # alias halt='sudo /sbin/halt' # git log detailed alias glg='git log --date-order --all --graph --format="%C(green)%h%Creset %C(yellow)%an%Creset %C(blue bold)%ar%Creset %C(red bold)%d%Creset%s"' # git log files changed alias glg2='git log --date-order --all --graph --name-status --format="%C(green)%H%Creset %C(yellow)%an%Creset %C(blue bold)%ar%Creset %C(red bold)%d%Creset%s"' # history alias h='history' alias clear_history='echo "" > ~/.zsh_history & exec $SHELL -l' # active connections alias connections='lsof -i' # Edit Vimrc alias vimrc="vim /Users/marko/Git/vimrc/vimrc" # Edit iTermocil alias edititermocil="code ~/.itermocil" # Desktop Alias alias desktop="cd ~/Desktop" # Top alias top="btop" # Iterm Shell Integration source ~/.iterm2_shell_integration.`basename $SHELL` compctl -g '~/.itermocil/*(:t:r)' itermocil # Now Playing alias nowplaying="sh ~/song.sh" # Send Nowplaying to Slack alias slackmusic="cd ~/Git/node-slack-fm-status && node run.js desmosthenes" # Close Finder Windows alias finder-close="osascript -e 'tell application \"Finder\" to close every window'" # Clean Brew alias brewski='brew update && brew upgrade && brew cleanup; brew doctor; brew missing; echo "Brewski Complete" | terminal-notifier -sound default -appIcon https://brew.sh/assets/img/homebrew-256x256.png -title "Homebrew"' # Start the Day alias communication="open -a 'Slack'; open -a 'Mimestream'; open -a 'Discord'; open -a 'Messages'; open -a 'WhatsApp';" # Check Active Connections alias check-open-connection="sudo lsof -iTCP -sTCP:LISTEN -n -P" # RIPGREP alias rgweb="rg --type-add 'web:*.{html,css,scss,js,php}'" # Reload Yabai alias yabai-reload='launchctl kickstart -k "gui/${UID}/homebrew.mxcl.yabai"' # Edit Yabairc alias yabairc="sudo vim ~/.yabairc" # Servers alias dobox="ssh USER@HOSTSERVER" alias archCakes="ssh USER@HOSTSERVER" alias spbox="ssh USER@HOSTSERVER" # Override cmus with sudo alias cmus="sudo cmus" # Run PHP server quickly # alias dev="kill -9 $(lsof -i:9999 -t); php -S localhost:9999" # Python 3 alias python=python3 # Git alias gg='cd ~/Git' # Eza unalias ls alias ls="eza -lhaGF --icons --git" # NPM Run Dev alias nrd="npm run dev" ### FZF # Another fd - cd into the selected directory # This one differs from the above, by only showing the sub directories and not # showing the directories within those. fd() { DIR=`find * -maxdepth 0 -type d -print 2> /dev/null | fzf --height 40% \ --border sharp \ --layout reverse \ --prompt '∷ ' \ --pointer ▶ \ --marker ⇒ ` \ && cd "$DIR" } # fdr - cd to selected parent directory fdr() { local declare dirs=() get_parent_dirs() { if [[ -d "${1}" ]]; then dirs+=("$1"); else return; fi if [[ "${1}" == '/' ]]; then for _dir in "${dirs[@]}"; do echo $_dir; done else get_parent_dirs $(dirname "$1") fi } local DIR=$(get_parent_dirs $(realpath "${1:-$PWD}") | fzf --height 40% \ --border sharp \ --layout reverse \ --prompt '∷ ' \ --pointer ▶ \ --marker ⇒ --tac) cd "$DIR" } # fcd - cd into the directory of the selected file fcd() { local file local dir file=$(fzf --height 40% \ --border sharp \ --layout reverse \ --prompt '∷ ' \ --pointer ▶ \ --marker ⇒ +m -q "$1") && dir=$(dirname "$file") && cd "$dir" } # fh - repeat command history fh() { eval $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf --height 40% \ --border sharp \ --layout reverse \ --prompt '∷ ' \ --pointer ▶ \ --marker ⇒ +s --tac | sed -E 's/ *[0-9]*\*? *//' | sed -E 's/\\/\\\\/g') } # fkill - kill processes - list only the ones you can kill. fkill() { local pid if [ "$UID" != "0" ]; then pid=$(ps -f -u $UID | sed 1d | fzf --height 40% \ --border sharp \ --layout reverse \ --prompt '∷ ' \ --pointer ▶ \ --marker ⇒ -m | awk '{print $2}') else pid=$(ps -ef | sed 1d | fzf --height 60% \ --border sharp \ --layout reverse \ --prompt '∷ ' \ --pointer ▶ \ --marker ⇒ -m | awk '{print $2}') fi if [ "x$pid" != "x" ] then echo $pid | xargs kill -${1:-9} fi } # fbr - checkout git branch (including remote branches) fbr() { local branches branch branches=$(git branch --all | grep -v HEAD) && branch=$(echo "$branches" | fzf-tmux -d $(( 2 + $(wc -l <<< "$branches") )) +m) && git checkout $(echo "$branch" | sed "s/.* //" | sed "s#remotes/[^/]*/##") } # fcoc - checkout git commit fcoc() { local commits commit commits=$(git log --pretty=oneline --abbrev-commit --reverse) && commit=$(echo "$commits" | fzf --tac +s +m -e) && git checkout $(echo "$commit" | sed "s/ .*//") } # fshow - git commit browser (& view commit contents) fshow() { git log --graph --color=always \ --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" | fzf --ansi --no-sort --reverse --tiebreak=index --bind=ctrl-s:toggle-sort \ --bind "ctrl-/:execute: (grep -o '[a-f0-9]\{7\}' | head -1 | xargs -I % sh -c 'git show --color=always % | less -R') << 'FZF-EOF' {} FZF-EOF" } # like normal z when used with arguments but displays an fzf prompt when used without. unalias z 2> /dev/null z() { [ $# -gt 0 ] && _z "$*" && return cd "$(_z -l 2>&1 | fzf --height 40% --nth 2.. --reverse --inline-info +s --tac --query "${*##-* }" | sed 's/^[0-9,.]* *//')" } bindkey "${key[Up]}" fzf-history-widget # f() { # sels=( "${(@f)$(fd "${fd_default[@]}" "${@:2}"| fzf)}" ) # test -n "$sels" && print -z -- "$1 ${sels[@]:q:q}" # }

In particular, I've been using fzf far more in my terminal workflow. It's truly made the experience much smoother, and eliminated quite a few painpoints. Can't recommend it enough.