Customizing .zshrc when using Oh My Zsh
Greetings!

Today we will look at the process of configuring the popular command shell ZSH⚙️ through the environment loading file .zshrc📝 when using the oh-my-zsh framework.

The demonstration presented in this article was performed in the environment of the Linux Mint 22🌱 distribution (Ubuntu 24🦍). Similarly, everything will work in other popular Linux distributions☝️.

Let’s go🏎.

TLDR

BASH
# install necessary utilities
sudo apt update && sudo apt install -y git curl zsh

# for a "colorful" terminal, install bat, exa, and grc
sudo apt install -y bat exa fzf grc || sudo apt install -y bat eza fzf grc

# backup existing .zshrc
[[ -f ~/.zshrc ]] && mv -v ~/.zshrc{,_backup}

# download ready-made .zshrc
curl -fsSL --output ~/.zshrc \
    https://raw.githubusercontent.com/r4ven-me/zshrc/main/.zshrc

# change default shell
[[ $SHELL == *zsh ]] || chsh -s /usr/bin/zsh

# apply changes for the current session
exec zsh
Click to expand and view more

Foreword

If you spend a lot of time in the Linux console/terminal🧑‍💻, you’ve probably heard about tools that simplify interaction with the command line and take the “user experience” to a “new level”🤔. One such tool is the ZSH shell and the oh-my-zsh🔥 framework created by skilled developers for its simple and convenient configuration.

Previously, I spent quite a lot of time bringing my shell to what I considered “ideal” or close to it🫠.

Below I will provide a detailed description of my ZSH configuration in the .zshrc file✍️, so you understand why you need it.

After that, I’ll show (a ridiculously simple🤷‍♂️) way to install and apply this configuration. All external dependencies, such as oh-my-zsh itself and additional plugins, will be installed automatically🦾 on the first launch of ZSH.

Demo of my configuration

BASH
Tab
Click to expand and view more

BASH
Ctrl+r
Click to expand and view more

BASH
history
Click to expand and view more

BASH
--help
Click to expand and view more

BASH
cat
Click to expand and view more

BASH
less
Click to expand and view more

BASH
tail
Click to expand and view more

BASH
tailf
Click to expand and view more

BASH
ls
Click to expand and view more

BASH
ss
Click to expand and view more

BASH
ping
Click to expand and view more

BASH
journalctl
Click to expand and view more

BASH
docker
Click to expand and view more

Convenient access to custom complex commands via the universal cmd function:

And much more. Now let’s move on to preparation and installation.

Preparation

Installing necessary packages

First, we need to install the zsh shell itself, the curl utility for web interaction, and the git version control system:

BASH
sudo apt update && sudo apt install -y git curl zsh
Click to expand and view more

Also (optionally), I recommend installing utilities for terminal output highlighting and convenient searching:

BASH
sudo apt install -y bat exa fzf grc || sudo apt install -y bat eza fzf grc
Click to expand and view more

Installing a powerline font for GUI sessions

For correct icon rendering in your terminal during a graphical session, you need to use a special monospace icon powerline font🤯, for example, from the Nerd fonts project.

My readers know that I prefer the Hack font ☝️. Here’s a simple example of how to install it:

BASH
# create font directory
sudo mkdir /usr/share/fonts/Hack

# download font archive
curl -fsSLO \
    $(curl -s https://api.github.com/repos/ryanoasis/nerd-fonts/releases/latest \
    | grep browser_download_url \
    | grep 'Hack.zip' \
    | cut -d  '"' -f 4)

# unpack archive, copy fonts to system
sudo unzip ./Hack.zip -d /usr/share/fonts/Hack/ && rm -f ./Hack.zip
Click to expand and view more

After installing the font, activate it in your terminal settings🛠.

In Gnome-terminal, this is done as follows:

Applying the .zshrc configuration

Back up the current .zshrc, if it exists:

BASH
# backup current .zshrc
[[ -f ~/.zshrc ]] && mv -v ~/.zshrc{,_backup}
Click to expand and view more

Create a new .zshrc in any convenient editor:

BASH
vim ~/.zshrc
Click to expand and view more

And populate it:

.zshrc
#======================================================
# Description: .zshrc configuration for oh-my-zsh
# Author: Ivan Cherniy
# Main website: https://r4ven.me
# Configuration note: https://r4ven.me/zshrc-config
#======================================================

#============================================
#             GENERAL SETTINGS
#============================================

# Add user directories to the PATH variable
if [[ -d "$HOME/bin" ]]; then PATH="$HOME/bin:$PATH"; fi
if [[ -d "$HOME/.bin" ]]; then PATH="$HOME/.bin:$PATH"; fi
if [[ -d "$HOME/.local/bin" ]]; then PATH="$HOME/.local/bin:$PATH"; fi
export PATH

export ZSH="$HOME/.config/oh-my-zsh"       # Path to Oh My Zsh installation
export ZSH_CUSTOM="$ZSH/custom"            # Path to Oh My Zsh custom directory
export TERM="xterm-256color"               # Set terminal type for better color support
# export TERM="screen-256color"             # Alternative terminal type (commented out)

have() {
    local utils=("$@")
    for util in "${utils[@]}"; do
        if ! command -v "$util" &> /dev/null; then return 1; fi
    done
    return 0
}

cmd_alias() {
  local cmd="$1"
  shift
  local replacement=( "$@" )
  if alias "$cmd" &> /dev/null; then unalias "$cmd"; fi
  if functions "$cmd" &> /dev/null; then unset -f "$cmd"; fi
  eval "$cmd() { command ${replacement[@]} \"\$@\"; }"
}

# Automatic installation of oh-my-zsh framework
if [[  ! -d "$ZSH" ]] && have "git"; then
    git clone https://github.com/ohmyzsh/ohmyzsh.git "$ZSH"
fi

# Oh-my-zsh theme selection
# More themes can be found here: https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
if [[ -n "$DISPLAY" || $(tty) == /dev/pts* ]] && have "curl"; then
    R4VEN_THEME="agnoster-r4ven.zsh-theme"
    if [[ ! -f "${ZSH_CUSTOM}/themes/${R4VEN_THEME}" ]]; then
        curl \
            --fail \
            --location \
            --show-error \
            --output "${ZSH_CUSTOM}"/themes/"${R4VEN_THEME}" \
            https://raw.githubusercontent.com/r4ven-me/zshrc/main/"${R4VEN_THEME}"
    fi
    # DASHES_COLOR=004
    DASHES_COLOR="blue"
    TIMER_FORMAT="%d"
    TIMER_THRESHOLD=0
    ZSH_THEME="${R4VEN_THEME%%.*}"         # Use this theme in graphical mode
    export VIRTUAL_ENV_DISABLE_PROMPT=1    # Disable standard virtualenv prompt
else
    ZSH_THEME="dpoggi"                     # Use 'noicon' theme in other cases, e.g., in console (tty)
fi

# Powerlevel10k theme (installation required)
# https://github.com/romkatv/powerlevel10k
# ZSH_THEME="powerlevel10k/powerlevel10k"

DISABLE_AUTO_UPDATE="true"                  # Disable automatic updates for Oh My Zsh (command: omz update)
COMPLETION_WAITING_DOTS="true"              # Show dots during command autocompletion

# Command history configuration
HIST_STAMPS="yyyy-mm-dd"                    # Add timestamp to command history
HISTFILE=~/.zsh_history                     # File to save history
HISTSIZE=10000                              # Maximum number of history entries in memory
SAVEHIST=10000                              # Maximum number of history entries to save to file
setopt hist_ignore_all_dups                 # Ignore duplicate entries in history
setopt share_history                        # Share history between sessions
setopt histignorespace                      # Ignore commands starting with a space

# Enable vi mode for the command line (emacs mode by default)
# set -o vi

#============================================
#                  PLUGINS
#============================================

plugins=(
    fzf                        # Integration with Fuzzy finder (Ctrl+r)
    git                        # Git aliases and functions
    sudo                       # Run/repeat last command with sudo (double Esc)
    docker                     # Docker command-line helper
    kubectl                    # Kubernetes command-line helper
    # zsh-autopair               # Automatic closing of parentheses and quotes
    zsh-completions            # Additional autocompletion scripts (Tab)
    zsh-autosuggestions        # Command suggestions based on history
    fast-syntax-highlighting   # Syntax highlighting for commands
    history-substring-search   # Search history by substring (up/down arrows)
)

# zsh-autopair: disable this plugin in MidnightCommander
# if ! [[ $(ps -o comm -h $PPID) =~ "^mc" ]]; then
#     plugins+=(zsh-autopair)
# fi

# Automatic installation of selected plugins
if [[ -d "$ZSH_CUSTOM" ]] && have "git"; then
    if [[ ! -d "${ZSH_CUSTOM}"/plugins/zsh-autopair ]]; then
        git clone https://github.com/hlissner/zsh-autopair \
            "${ZSH_CUSTOM}"/plugins/zsh-autopair
    fi
    
    if [[ ! -d "${ZSH_CUSTOM}"/plugins/zsh-completions ]]; then
        git clone https://github.com/zsh-users/zsh-completions \
            "${ZSH_CUSTOM}"/plugins/zsh-completions
    fi
    
    if [[ ! -d "${ZSH_CUSTOM}"/plugins/zsh-autosuggestions ]]; then
        git clone https://github.com/zsh-users/zsh-autosuggestions \
            "${ZSH_CUSTOM}"/plugins/zsh-autosuggestions
    fi
    
    if [[ ! -d "${ZSH_CUSTOM}"/plugins/fast-syntax-highlighting ]]; then
        git clone https://github.com/zdharma-continuum/fast-syntax-highlighting \
            "${ZSH_CUSTOM}"/plugins/fast-syntax-highlighting
        
        reset
    fi
fi

#============================================
#              OH-MY-ZSH INITIALIZATION
#============================================

source "${ZSH}"/oh-my-zsh.sh                # Initialize Oh My Zsh framework

autoload -Uz compinit && compinit           # Initialize and enable autocompletion system

if [[ -r "${HOME}"/.profile ]]; then
    source "${HOME}"/.profile               # Load '.profile' if it exists
fi

#============================================
#              APPLICATIONS AND UTILITIES
#============================================

# Python
cmd_alias "python" "python3"

# Network
cmd_alias "p8" "ping" "-c3" "8.8.8.8"
cmd_alias "ip" "ip" "--color"

# Text editor settings
if have "nvim"; then
    export EDITOR="$(command -v nvim)"
    export VISUAL="$(command -v nvim)"
    alias vim="nvim"
    alias n="nvim"
    alias N="sudo nvim"
elif have "vim"; then
    export EDITOR="$(command -v vim)"
    export VISUAL="$(command -v vim)"
    alias v="vim"
    alias V="sudo vim"
fi

# FZF configuration with Nord theme colors
if have "fzf"; then
    export FZF_DEFAULT_OPTS="--exact"
    export FZF_DEFAULT_OPTS=$FZF_DEFAULT_OPTS'
        --color=fg:#e5e9f0,bg:#2e3440,hl:#81a1c1
        --color=fg+:#e5e9f0,bg+:#2e3440,hl+:#81a1c1
        --color=info:#eacb8a,prompt:#bf6069,pointer:#b48dac
        --color=marker:#a3be8b,spinner:#b48dac,header:#a3be8b
        --color=border:#5e81ac
        --border=rounded
    '
fi

# Defining a variable with the name of the utility: bat or batcat
# if have "batcat"; then cmd_alias "bat" "batcat"; fi
if have "batcat"; then bat="batcat"; else bat="bat" fi

# Usage bat instead of cat, less, man, --help, tail -f
# See more: https://r4ven.me/bat-exa-config
if have "$bat"; then
    export COLORTERM="truecolor"
    export BAT_THEME="Nord"
    export MANPAGER="sh -c 'col -bx | $bat --language=man --style=plain'"  # Command to view man pages
    export MANROFFOPT="-c"  # Disabling line wrapping in man
    cmd_alias "cat" "$bat" "--style=plain" "--paging=never"
    cmd_alias "less" "$bat" "--paging=always"
    if [[ $SHELL == *zsh ]]; then # global alias "--help" if zsh
        alias -g -- --help='--help 2>&1 | "$bat" --language=help --style=plain'
    fi
    help() { "$@" --help 2>&1 | "$bat" --language=help --style=plain; }
    tailf() { tail -f "$@" | "$bat" --paging=never --language=log; }
    batdiff() { git diff --name-only --relative --diff-filter=d | xargs "$bat" --diff; }
fi

# Use exa instead of ls
# More details: https://r4ven.me/bat-exa-config
if have "exa"; then
    if [[ -n "$DISPLAY" || $(tty) == /dev/pts* ]]; then # display icons if pseudo-terminal
        cmd_alias "ls" "exa" "--group" "--header" "--icons" "--time-style=long-iso"
    else
        cmd_alias "ls" "exa" "--group" "--header" "--time-style=long-iso"
    fi
    alias l="ls"
    alias ll="ls --long"
    alias lll="ls --long --all"
    alias llll="ls -lbHigUmuSa --sort=modified --time-style=long-iso"
    alias lm="ls --long --all --sort=modified"
    alias lt="ls --tree"
    alias lr="ls --recurse"
    alias lg="ls --long --git --sort=modified"
fi

# Highlight output of various commands
if have "grc" && tty -s && [[ -n "$TERM" && "$TERM" != dumb ]]; then
    GRC_UTILS=(
        configure ping traceroute gcc make netstat stat ss diff
        wdiff last who cvs mount findmnt mtr ps dig ifconfig
        df du env systemctl iptables lspci lsblk lsof blkid
        id iostat sar fdisk free docker journalctl kubectl
        sensors sysctl tail head tcpdump tune2fs lsmod lsattr
        semanage getsebool ulimit vmstat dnf nmap uptime w
        getfacl ntpdate showmount apache iwconfig lolcat whois
        go sockstat
        #ls ip
    )
    for cmd in "${GRC_UTILS[@]}"; do
        if have "$cmd"; then
            cmd_alias "$cmd" "grc" "--stderr" "--stdout" "$cmd"
        fi
    done
fi

# APT
if have "apt"; then
    alias AU="sudo apt update"
    alias AUP="sudo apt upgrade"
    alias AR="sudo apt autoremove"
    alias AI="sudo apt install"
    alias AUI="sudo apt update && sudo apt install"
fi

# Ansible
if have "ansible"; then
    AP() { ansible-playbook ~/ansible/playbooks/"$@"; }
    alias AC="ansible-console"
fi

# Tmux
if have "tmux"; then
    alias T="tmux attach -t Work || tmux new -s Work"
    alias TT="sudo tmux attach -t Work! || sudo tmux new -s Work!"
fi

# ShellGPT
if have "sgpt"; then
    export LITELLM_LOG="ERROR"
    G() { sgpt --chat temp "$*"; }
    GS() { sgpt --shell "$*"; }
    GC() {
        echo ""
        sgpt --code --no-md "$*" | "$bat" --language=sh --paging=never --style=plain
        echo ""
    }
    alias GG="sgpt --repl temp"
fi

# Defines the 'cmd' function, which executes custom commands from a list
# It takes one argument - the command name and inserts it into the command line
# Use the TAB key for suggestions
cmd() {
    local cmd_name="${1}"
    typeset -A cmd_list

    # Associative array to store the list of commands
    # Keys are command names, values are the commands themselves
    cmd_list=(
        ps_top5_cpu "ps --sort=-%cpu -eo user,pid,ppid,state,comm | head -n6"
        ps_top5_mem "ps --sort=-%mem -eo user,pid,ppid,state,comm | head -n6"
        ps_zombie "ps -eo user,pid,ppid,state,comm | awk '\$4=="Z" {print \$3}'"
        cron_add_task '{ crontab -l; echo "0 3 * * 0 ls -l &> dirs.txt"; } | crontab -'
        du_top20 'du -x -h / 2> /dev/null | sort -rh | head -n 20'
        df_80 "df -h | awk '\$5 ~ /^8[0-9]%/ {print $6}'"
        git_init 'git init --initial-branch=main && git remote add origin ssh://git@github.com/r4ven-me/reponame.git'
        journal_vacuum 'journalctl --vacuum-size=800M'
        lsof_opened 'lsof +D /opt'
    )

    # Check if the command exists in the array, or if help is requested
    if [[ -z ${cmd_list[$cmd_name]} || -z "$cmd_name" || "$cmd_name" == "-h" ]]; then
        # Display the list of available commands
        echo "AVAILABLE COMMANDS:\n"
        printf "%-20s %s\n" "Key" "Command"
        echo "----------------------------"
        # Iterate through all keys in the array and display them
        for key in "${(@k)cmd_list}"; do
            printf "%-20s %s\n" "$key" "${cmd_list[$key]}"
            # echo "------------------"
        done | sort
        return 0
    else
        # If the command is found, insert it into the command line
        print -zr "${cmd_list[$cmd_name]}"
        return 0
    fi
}

# Function for command autocompletion
_cmd_completion() {
    local -a keys
    keys=($(cmd -h | awk 'NR>4 {print $1}'))  # Extract keys from help output
    compadd "$@" -- "${keys[@]}"
}

# Register the autocompletion function for the `cmd` command
compdef _cmd_completion cmd

#============================================
#                  PROMPT
#============================================

# Remove user@host context from the prompt when DISPLAY is set
if [[ -n "$DISPLAY" && -z "$SSH_CONNECTION" ]]; then
    prompt_context() { }                    # Empty function to disable context
fi
Click to expand and view more

Close/save and launch zsh in the current session:

PLAINTEXT
exec zsh
Click to expand and view more

The process of downloading missing components to the ~/.config/oh-my-zsh directory will begin:

If you are in a graphical session, you will have a minimalistic prompt:

Otherwise, it will be like this:

The console session will use a theme without icons:

At this point, we have simply launched the zsh shell in the current session☝️. To make zsh your default shell (if it isn’t already), execute the command:

BASH
[[ $SHELL == *zsh ]] || chsh -s /usr/bin/zsh
Click to expand and view more

Done. For the changes to apply correctly, it is recommended to log out of the current session and log back in🚶‍➡️.

Afterword

This time, we thoroughly examined how to configure the behavior of the ZSH shell in the .zshrc file when using the popular oh-my-zsh framework😌.

In my opinion, customizing one’s workspace (including the shell) significantly increases efficiency🧑‍💻. Unless, of course, one becomes fanatical about it😉. Many ignore this aspect, preferring default settings. I can’t say this is bad; it’s just that, with some experience, I’ve realized: it’s better to spend a little (or a lot) of time on setup👨‍🔧 and then simply use the resulting configuration wherever possible, thereby solving various tasks with greater convenience and fewer nerves😎.

For example, when typing a command in the terminal, you constantly forget (or don’t know🤷‍♂️) what flags it has and what they do. You have to interrupt your typing to look up the help. In the case of my configuration, for most popular commands, it’s enough to just press Tab to see a hint of the flags, which can also be “tabbed through”👌. This also includes the convenience of working with command history and so on😏.

Useful materials

Copyright Notice

Author: Иван Чёрный

Link: https://r4ven.me/en/dots/tonkaya-nastrojka-zshrc-pri-ispolzovanii-oh-my-zsh/

License: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Start searching

Enter keywords to search articles

↑↓
ESC
⌘K Shortcut