Post

Automate Your Zsh Setup- Scripted Installation of Oh My Zsh, Auto-Suggestions & Syntax Highlighting

Ready for a smarter terminal? This guide provides a comprehensive shell script to completely automate the installation and configuration of Zsh as your default shell, set up Oh My Zsh, and integrate must-have plugins like zsh-autosuggestions and zsh-syntax-highlighting. Get a highly functional and beautiful command-line environment with minimal effort, simply by running a file.

Automate Your Zsh Setup- Scripted Installation of Oh My Zsh, Auto-Suggestions & Syntax Highlighting

Setup Z shell with Auto-Suggestions & Syntax Highlighting for all Linux distributions

Full Automated Zsh Setup

Here’s a complete setup_zsh.sh bash script that you can curl to any (deb and rpm) based Linux to perform the full install process:

Run this single curl command in bash shell:

1
curl -sL installzsh.vercel.app | bash
  • OR
1
curl -fsSL https://raw.githubusercontent.com/janak0ff/zsh/main/setup_zsh.sh | bash

This prompts you to enter your sudo password and after the installation is complete, Just restart your terminal and you are good to go.

1
zsh

Manual zsh Setup

Please save the following content into a file named setup_zsh.sh (or any .sh extension), then make it executable using chmod +x setup_zsh.sh, and run it with ./setup_zsh.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
#!/bin/bash

# =============================================================================
# Enhanced Zsh + Plugins + Git Prompt Setup Script
# Supports Debian/Ubuntu, RHEL/CentOS/Fedora, Arch Linux, and openSUSE systems
# =============================================================================

set -e  # Exit on any error

# === COLOR FUNCTIONS ===
info() {
    echo -e "\n\033[1;32m==> $1\033[0m"
}

warn() {
    echo -e "\n\033[1;33m==> $1\033[0m"
}

error() {
    echo -e "\n\033[1;31m==> ERROR: $1\033[0m" >&2
}

# === PACKAGE MANAGEMENT ===
detect_pkg_manager() {
    if command -v apt-get &>/dev/null; then
        echo "apt"
    elif command -v dnf &>/dev/null; then
        echo "dnf"
    elif command -v yum &>/dev/null; then
        echo "yum"
    elif command -v zypper &>/dev/null; then
        echo "zypper"
    elif command -v pacman &>/dev/null; then
        echo "pacman"
    else
        error "Could not detect package manager"
        exit 1
    fi
}

install_packages() {
    local pkg_manager="$1"
    shift
    local packages=("$@")

    info "Installing packages: ${packages[*]}"

    case "$pkg_manager" in
        apt)
            sudo apt update && sudo apt install -y "${packages[@]}"
            ;;
        dnf)
            sudo dnf install -y "${packages[@]}"
            ;;
        yum)
            sudo yum install -y "${packages[@]}"
            ;;
        zypper)
            sudo zypper refresh && sudo zypper install -y "${packages[@]}"
            ;;
        pacman)
            sudo pacman -Sy --noconfirm "${packages[@]}"
            ;;
    esac
}

# === SYSTEM CHECKS ===
check_sudo() {
    if ! command -v sudo &>/dev/null; then
        error "sudo not found. Please install sudo or run as root."
        exit 1
    fi

    if ! sudo -v &>/dev/null; then
        error "Sudo access required. Please run with sudo privileges."
        exit 1
    fi
}

# === ZSH HISTORY DOWNLOAD ===
download_zsh_history() {
    info "Downloading .zsh_history to home directory..."

    local history_url="https://raw.githubusercontent.com/janak0ff/zsh/main/.zsh_history"
    local history_file="$HOME/.zsh_history"

    # Check if wget or curl is available
    if command -v wget &>/dev/null; then
        if wget -q -O "$history_file" "$history_url"; then
            info "✅ Successfully downloaded .zsh_history using wget"
        else
            warn "❌ Failed to download .zsh_history using wget"
            return 1
        fi
    elif command -v curl &>/dev/null; then
        if curl -s -o "$history_file" "$history_url"; then
            info "✅ Successfully downloaded .zsh_history using curl"
        else
            warn "❌ Failed to download .zsh_history using curl"
            return 1
        fi
    else
        warn "❌ Neither wget nor curl available. Skipping .zsh_history download."
        return 1
    fi

    # Set appropriate permissions
    if [ -f "$history_file" ]; then
        chmod 600 "$history_file"
        info "✅ Set secure permissions on .zsh_history"
        return 0
    else
        warn "❌ Downloaded .zsh_history file not found"
        return 1
    fi
}

# === SHELL SETUP ===
setup_zsh_shell() {
    local current_shell="$SHELL"
    local zsh_path="$(command -v zsh)"

    if [ -z "$zsh_path" ]; then
        error "zsh not found in PATH. Please install zsh first."
        exit 1
    fi

    if [[ "$current_shell" != *zsh ]]; then
        warn "To set zsh as your default shell, run: chsh -s $zsh_path"
        info "You can also start zsh temporarily by typing 'zsh'"
    else
        info "Zsh is already the default shell."
    fi
}

setup_auto_start() {
    local shell_rc=""

    # Determine which shell config file to use
    case "$SHELL" in
        *bash) shell_rc="$HOME/.bashrc" ;;
        *zsh) shell_rc="$HOME/.zshrc" ;;
        *) 
            warn "Unknown shell: $SHELL. Cannot setup auto-start."
            return
            ;;
    esac

    # Create shell rc if it doesn't exist
    if [ ! -f "$shell_rc" ]; then
        touch "$shell_rc"
        info "Created $shell_rc"
    fi

    # Add auto-start if not already present
    if ! grep -qxF '[ -x "$(command -v zsh)" ] && exec zsh' "$shell_rc"; then
        echo '# Auto-start zsh if available' >> "$shell_rc"
        echo '[ -x "$(command -v zsh)" ] && exec zsh' >> "$shell_rc"
        info "✅ Added auto-start of zsh to $shell_rc"
    else
        info "✅ Auto-start already configured in $shell_rc"
    fi
}

# === PLUGIN MANAGEMENT ===
install_plugin() {
    local plugin_dir="$1"
    local repo_url="$2"
    local plugin_name="$3"

    if [ ! -d "$plugin_dir/$plugin_name" ]; then
        info "Installing $plugin_name..."
        if git clone --depth 1 "$repo_url" "$plugin_dir/$plugin_name" 2>/dev/null; then
            info "✅ Successfully installed $plugin_name"
        else
            warn "❌ Failed to install $plugin_name"
            return 1
        fi
    else
        info "✅ $plugin_name already installed."
    fi
    return 0
}

# === ZSH CONFIGURATION ===
generate_zshrc() {
    local zshrc="$HOME/.zshrc"

    # Backup existing zshrc if it exists
    if [ -f "$zshrc" ]; then
        local backup="$zshrc.backup.$(date +%Y%m%d_%H%M%S)"
        cp "$zshrc" "$backup"
        info "✅ Backed up existing .zshrc to $backup"
    fi

    info "Generating enhanced ~/.zshrc..."

    cat > "$zshrc" <<'EOF'
# =============================================================================
# ENHANCED ZSH CONFIGURATION
# Generated by automated setup script
# =============================================================================

# === GIT BRANCH/STATUS IN PROMPT ===
autoload -Uz vcs_info
precmd() { vcs_info }
setopt prompt_subst

# Git status configuration
zstyle ':vcs_info:*' enable git
zstyle ':vcs_info:*' check-for-changes true
zstyle ':vcs_info:git:*' stagedstr '✔'
zstyle ':vcs_info:git:*' unstagedstr '✚'
zstyle ':vcs_info:git:*' untrackedstr '?'  # Changed from emoji for better compatibility
zstyle ':vcs_info:git:*' formats ' (%b%u%c)'

# Prompt: user@hostname + current directory + git status
PROMPT='%n@%m %~${vcs_info_msg_0_} > '

# === SHELL OPTIONS ===
setopt auto_cd                    # Change to directory by typing its name
setopt hist_expire_dups_first     # Remove duplicates first when history fills up
setopt hist_ignore_space          # Don't save commands starting with space
setopt hist_verify                # Show history expansion before executing
setopt append_history             # Append to history file
setopt share_history              # Share history between sessions

# History configuration
HISTFILE="$HOME/.zsh_history"
HISTSIZE=5000
SAVEHIST=5000

# === AUTOSUGGESTIONS ===
if [ -f "$HOME/.zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh" ]; then
    source "$HOME/.zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh"
    ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#999999"
    ZSH_AUTOSUGGEST_STRATEGY=(history completion)
else
    echo "⚠️  zsh-autosuggestions not found. Run setup script to install."
fi

# === SYNTAX HIGHLIGHTING ===
if [ -f "$HOME/.zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" ]; then
    source "$HOME/.zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
    ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern)
else
    echo "⚠️  zsh-syntax-highlighting not found. Run setup script to install."
fi

# === ENVIRONMENT VARIABLES ===
export EDITOR="${EDITOR:-vim}"           # Default editor
export VISUAL="${VISUAL:-$EDITOR}"       # Visual editor
export PATH="$HOME/.local/bin:$PATH"     # Add local bin to PATH

# === ALIASES ===
# File listing
alias ll='ls -lAh'               # Long list with almost all files, human readable
alias la='ls -A'                 # List all including hidden
alias l='ls -CF'                 # Column format with file type indicators

# Grep with colors
alias grep='grep --color=auto'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'

# Navigation
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'

# Safety (interactive mode)
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# === COMPLETION SYSTEM ===
# Initialize and configure completions
autoload -Uz compinit
compinit

# Completion settings
zstyle ':completion:*' menu select
zstyle ':completion:*' rehash true

# === NODE VERSION MANAGER (NVM) ===
export NVM_DIR="$HOME/.nvm"
if [ -s "$NVM_DIR/nvm.sh" ]; then
    \. "$NVM_DIR/nvm.sh"
fi
if [ -s "$NVM_DIR/bash_completion" ]; then
    \. "$NVM_DIR/bash_completion"
fi

# === LS COLORS ===
# Enable colors for ls if available
if command -v dircolors >/dev/null 2>&1; then
    eval "$(dircolors -b)"
    alias ls='ls --color=auto'
fi
EOF

    info "✅ Generated enhanced .zshrc configuration"
}

# === USER PROMPT ===
prompt_for_history() {
    while true; do
        read -r -p "Do you want to download zsh history? [Y/n] " response
        case "$response" in
            [yY]|[yY][eE][sS]|"")
                return 0
                ;;
            [nN]|[nN][oO])
                return 1
                ;;
            *)
                echo "❌ Invalid input. Please answer 'y' or 'n'."
                ;;
        esac
    done
}

# === MAIN SCRIPT ===
main() {
    info "🚀 Starting Enhanced Zsh Setup..."

    # Prompt for history download
    if prompt_for_history; then
        download_zsh_history
    else
        info "Skipping history download."
    fi

    # Detect package manager
    info "Detecting package manager..."
    PKG_MANAGER=$(detect_pkg_manager)
    info "Detected package manager: $PKG_MANAGER"

    # Check sudo access
    info "Checking sudo access..."
    check_sudo

    # Install required packages
    info "Installing zsh, git, curl, and wget..."
    case "$PKG_MANAGER" in
        apt) 
            install_packages "$PKG_MANAGER" zsh git curl wget
            ;;
        dnf|yum) 
            install_packages "$PKG_MANAGER" zsh git curl wget
            ;;
        zypper) 
            install_packages "$PKG_MANAGER" zsh git curl wget
            ;;
        pacman)
            install_packages "$PKG_MANAGER" zsh git curl wget
            ;;
    esac

    # Setup shell configuration
    setup_zsh_shell

    # Setup auto-start
    info "Configuring auto-start of zsh..."
    setup_auto_start

    # Plugin setup
    info "Setting up Zsh plugins..."
    ZSH_PLUGIN_DIR="$HOME/.zsh/plugins"
    mkdir -p "$ZSH_PLUGIN_DIR"

    install_plugin "$ZSH_PLUGIN_DIR" \
        "https://github.com/zsh-users/zsh-autosuggestions" \
        "zsh-autosuggestions"

    install_plugin "$ZSH_PLUGIN_DIR" \
        "https://github.com/zsh-users/zsh-syntax-highlighting.git" \
        "zsh-syntax-highlighting"

    # Generate enhanced .zshrc
    generate_zshrc

    # Completion message
    info "✅ Zsh setup completed successfully!"
    echo
    echo "🎯 NEXT STEPS:"
    echo "   - Run 'zsh' to start using Zsh immediately"
    echo "   - Run 'chsh -s $(command -v zsh)' to make Zsh your default shell"
    echo "   - Restart your terminal for all changes to take effect"
    echo "   - Your configuration includes:"
    echo "     ✓ Git-aware prompt with username@hostname"
    echo "     ✓ Syntax highlighting"
    echo "     ✓ Autosuggestions"
    echo "     ✓ Enhanced completions"
    echo "     ✓ Useful aliases"
    echo
    echo "🔧 To customize further, edit: ~/.zshrc"
}

# Handle script interruption
trap 'error "Script interrupted by user"; exit 1' INT TERM

# Run main function
main "$@"
This post is licensed under CC BY 4.0 by the author.