Last active
May 16, 2026 12:47
-
-
Save SmileMachine/4b0ef5d6fb57873fd6bd9b04ef93d612 to your computer and use it in GitHub Desktop.
Install Oh My Zsh and some useful plugins on a new machine.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # !!! This script is used specially for first install of omz on a new machine | |
| # !!! All configurations in .zshrc will be replaced !!! (A backup file will be created) | |
| # Use -y to skip this script's confirmation prompt. | |
| set -euo pipefail | |
| # Terminal colors | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[0;33m' | |
| NC='\033[0m' # No Color | |
| PKG_INSTALL_CMD=() | |
| PKG_MANAGER="" | |
| # Error handling function | |
| error_exit() { | |
| echo -e "${RED}[ERROR] $1${NC}" >&2 | |
| exit 1 | |
| } | |
| # Check if command exists | |
| check_command() { | |
| command -v "$1" >/dev/null 2>&1 | |
| } | |
| find_brew() { | |
| local brew_path | |
| for brew_path in /opt/homebrew/bin/brew /usr/local/bin/brew; do | |
| if [ -x "$brew_path" ]; then | |
| printf '%s\n' "$brew_path" | |
| return 0 | |
| fi | |
| done | |
| command -v brew 2>/dev/null | |
| } | |
| ensure_homebrew() { | |
| local brew_cmd | |
| if brew_cmd=$(find_brew); then | |
| export PATH="$(dirname "$brew_cmd"):$PATH" | |
| return 0 | |
| fi | |
| if ! check_command curl; then | |
| error_exit "curl required to install Homebrew" | |
| fi | |
| echo -e "${YELLOW}[INFO] Installing Homebrew for macOS${NC}" | |
| /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
| if brew_cmd=$(find_brew); then | |
| export PATH="$(dirname "$brew_cmd"):$PATH" | |
| return 0 | |
| fi | |
| error_exit "Homebrew installed, but brew was not found in PATH, /opt/homebrew/bin, or /usr/local/bin" | |
| } | |
| # Show warning and get confirmation | |
| show_warning() { | |
| echo -e "${RED}╔══════════════════════════════════════════════════════════════╗${NC}" | |
| echo -e "${RED}║ WARNING ║${NC}" | |
| echo -e "${RED}╠══════════════════════════════════════════════════════════════╣${NC}" | |
| echo -e "${RED}║ This script is for FIRST INSTALL of OMZ on a NEW machine ║${NC}" | |
| echo -e "${RED}║ All .zshrc configurations will be REPLACED! ║${NC}" | |
| echo -e "${RED}║ (A backup will be created) ║${NC}" | |
| echo -e "${RED}╚══════════════════════════════════════════════════════════════╝${NC}" | |
| echo | |
| echo -e "${YELLOW}Are you sure you want to continue?${NC}" | |
| read -p "Type 'YES' in uppercase to confirm: " confirmation | |
| if [[ $confirmation != "YES" ]]; then | |
| echo -e "${YELLOW}[INFO] Installation aborted by user${NC}" | |
| exit 0 | |
| fi | |
| echo -e "${GREEN}[INFO] Continuing with installation...${NC}" | |
| echo | |
| } | |
| # Detect OS and package manager | |
| detect_pkg_manager() { | |
| local optional=false | |
| local brew_cmd | |
| if [[ "${1:-}" == "--optional" ]]; then | |
| optional=true | |
| fi | |
| detect_failed() { | |
| if [[ $optional == true ]]; then | |
| return 1 | |
| fi | |
| error_exit "$1" | |
| } | |
| case "$(uname -sr)" in | |
| Linux*) | |
| if [ -f /etc/os-release ]; then | |
| . /etc/os-release | |
| case "$ID" in | |
| debian|ubuntu|linuxmint|elementary|pop|kali|raspbian) | |
| PKG_INSTALL_CMD=(sudo apt install -y) | |
| PKG_MANAGER="apt" | |
| ;; | |
| fedora|rhel|centos|rocky|almalinux) | |
| if check_command dnf; then | |
| PKG_INSTALL_CMD=(sudo dnf install -y) | |
| PKG_MANAGER="dnf" | |
| else | |
| PKG_INSTALL_CMD=(sudo yum install -y) | |
| PKG_MANAGER="yum" | |
| fi | |
| ;; | |
| arch|manjaro) | |
| PKG_INSTALL_CMD=(sudo pacman -Sy --noconfirm) | |
| PKG_MANAGER="pacman" | |
| ;; | |
| opensuse*|suse) | |
| PKG_INSTALL_CMD=(sudo zypper install -y) | |
| PKG_MANAGER="zypper" | |
| ;; | |
| alpine) | |
| PKG_INSTALL_CMD=(sudo apk add) | |
| PKG_MANAGER="apk" | |
| ;; | |
| void) | |
| PKG_INSTALL_CMD=(sudo xbps-install -Sy) | |
| PKG_MANAGER="xbps" | |
| ;; | |
| *) | |
| detect_failed "Unsupported OS: $ID" || return 1 | |
| ;; | |
| esac | |
| else | |
| detect_failed "Could not identify Linux distribution" || return 1 | |
| fi | |
| ;; | |
| Darwin*) | |
| if [[ $optional == true ]]; then | |
| if brew_cmd=$(find_brew); then | |
| export PATH="$(dirname "$brew_cmd"):$PATH" | |
| else | |
| return 1 | |
| fi | |
| else | |
| ensure_homebrew | |
| fi | |
| PKG_INSTALL_CMD=(brew install) | |
| PKG_MANAGER="brew" | |
| ;; | |
| CYGWIN*|MINGW*|MSYS*) | |
| PKG_INSTALL_CMD=(pacman -S --noconfirm) | |
| PKG_MANAGER="pacman" | |
| ;; | |
| *) | |
| detect_failed "Unsupported system: $(uname -sr)" || return 1 | |
| ;; | |
| esac | |
| } | |
| # Install required dependencies | |
| install_dependencies() { | |
| local required_deps=() | |
| ! check_command curl && required_deps+=(curl) | |
| ! check_command git && required_deps+=(git) | |
| ! check_command zsh && required_deps+=(zsh) | |
| if [ ${#required_deps[@]} -gt 0 ]; then | |
| if [ ${#PKG_INSTALL_CMD[@]} -eq 0 ]; then | |
| detect_pkg_manager | |
| fi | |
| echo -e "${YELLOW}[INFO] Installing dependencies: ${required_deps[*]}${NC}" | |
| "${PKG_INSTALL_CMD[@]}" "${required_deps[@]}" || error_exit "Failed to install dependencies" | |
| fi | |
| } | |
| # Install a Zsh plugin if it does not already exist | |
| install_plugin() { | |
| local plugins_dir="$1" | |
| local repo="$2" | |
| local plugin_name="${3:-$(basename "$repo")}" | |
| if [ ! -d "$plugins_dir/$plugin_name" ]; then | |
| echo -e "${YELLOW}[INFO] Installing plugin: $plugin_name${NC}" | |
| git clone --depth=1 "$repo" "$plugins_dir/$plugin_name" || | |
| error_exit "Failed to install plugin: $plugin_name" | |
| else | |
| echo -e "${GREEN}[INFO] Plugin exists: $plugin_name${NC}" | |
| fi | |
| } | |
| # Install Zsh plugins used by the generated .zshrc | |
| install_zsh_plugins() { | |
| local plugins_dir="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins" | |
| mkdir -p "$plugins_dir" | |
| install_plugin "$plugins_dir" https://github.com/zsh-users/zsh-autosuggestions | |
| install_plugin "$plugins_dir" https://github.com/zdharma-continuum/fast-syntax-highlighting | |
| } | |
| # Install fzf if it is missing | |
| install_fzf() { | |
| if check_command fzf; then | |
| echo -e "${GREEN}[INFO] fzf already exists${NC}" | |
| return | |
| fi | |
| echo -e "${YELLOW}[INFO] Installing fzf${NC}" | |
| if [ -z "$PKG_MANAGER" ]; then | |
| detect_pkg_manager --optional || PKG_MANAGER="" | |
| fi | |
| case "$PKG_MANAGER" in | |
| apt) sudo apt install -y fzf ;; | |
| dnf|yum) sudo "$PKG_MANAGER" install -y fzf ;; | |
| pacman) sudo pacman -Sy --noconfirm fzf ;; | |
| apk) sudo apk add fzf ;; | |
| zypper) sudo zypper install -y fzf ;; | |
| xbps) sudo xbps-install -Sy fzf ;; | |
| brew) brew install fzf ;; | |
| *) | |
| if [ -d "$HOME/.fzf" ]; then | |
| echo -e "${GREEN}[INFO] ~/.fzf already exists${NC}" | |
| else | |
| git clone --depth 1 https://github.com/junegunn/fzf.git "$HOME/.fzf" | |
| fi | |
| "$HOME/.fzf/install" --all --no-update-rc | |
| ;; | |
| esac | |
| } | |
| # Main installation function | |
| main() { | |
| # Show warning | |
| AUTO_CONFIRM=false | |
| for arg in "$@"; do | |
| if [[ "$arg" == "-y" ]]; then | |
| AUTO_CONFIRM=true | |
| break | |
| fi | |
| done | |
| if [[ $AUTO_CONFIRM == true ]]; then | |
| echo -e "${GREEN}[INFO] Auto-confirm enabled, skipping warnings${NC}" | |
| else | |
| show_warning | |
| fi | |
| install_dependencies | |
| # Check current shell | |
| local current_shell=$(basename "$SHELL") | |
| if [[ $current_shell == "zsh" ]]; then | |
| echo -e "${GREEN}[INFO] Already running in Zsh${NC}" | |
| else | |
| if ! check_command zsh; then | |
| error_exit "Zsh installation failed" | |
| else | |
| echo -e "${GREEN}[INFO] Zsh installed successfully${NC}" | |
| fi | |
| fi | |
| # Install Oh My Zsh | |
| if [ ! -d "$HOME/.oh-my-zsh" ]; then | |
| echo -e "${YELLOW}[INFO] Installing Oh My Zsh${NC}" | |
| if check_command curl; then | |
| sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended | |
| elif check_command wget; then | |
| sh -c "$(wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh -O -)" "" --unattended | |
| else | |
| error_exit "curl or wget required to install Oh My Zsh" | |
| fi | |
| else | |
| echo -e "${GREEN}[INFO] Oh My Zsh already exists${NC}" | |
| fi | |
| # Install plugins | |
| install_zsh_plugins | |
| # Install fzf | |
| install_fzf | |
| # Configure Zsh | |
| local zshrc="$HOME/.zshrc" | |
| local backup_file="" | |
| echo -e "${YELLOW}[INFO] Configuring $zshrc${NC}" | |
| # Backup existing config | |
| if [ -f "$zshrc" ]; then | |
| backup_file="${zshrc}.backup.$(date +%s)" | |
| cp "$zshrc" "$backup_file" | |
| echo -e "${GREEN}[INFO] Old .zshrc saved to $backup_file${NC}" | |
| fi | |
| # Generate new configuration | |
| cat << "EOZSH" > "$zshrc" | |
| # Basic configuration | |
| export ZSH="$HOME/.oh-my-zsh" | |
| ZSH_THEME="robbyrussell" | |
| HYPHEN_INSENSITIVE="true" | |
| COMPLETION_WAITING_DOTS="true" | |
| # Do not prompt for update when start, only check and reminder. | |
| zstyle ':omz:update' mode reminder | |
| # Plugin configuration | |
| plugins=( | |
| git | |
| zsh-autosuggestions | |
| fast-syntax-highlighting | |
| fzf | |
| ) | |
| # Load Oh My Zsh | |
| source $ZSH/oh-my-zsh.sh | |
| # Fix for slow pasting | |
| # https://github.com/zsh-users/zsh-autosuggestions/issues/238 | |
| pasteinit() { | |
| OLD_SELF_INSERT=${${(s.:.)widgets[self-insert]}[2,3]} | |
| zle -N self-insert url-quote-magic | |
| } | |
| pastefinish() { | |
| zle -N self-insert $OLD_SELF_INSERT | |
| } | |
| zstyle :bracketed-paste-magic paste-init pasteinit | |
| zstyle :bracketed-paste-magic paste-finish pastefinish | |
| EOZSH | |
| # Set default shell if not already zsh | |
| if [[ $current_shell != "zsh" ]]; then | |
| echo -e "${YELLOW}[INFO] Setting Zsh as default shell${NC}" | |
| if ! chsh -s "$(command -v zsh)"; then | |
| echo -e "${YELLOW}[WARNING] Could not change default shell. You may need to run manually:" | |
| echo -e "chsh -s $(command -v zsh)" | |
| echo -e "or edit /etc/passwd${NC}" | |
| fi | |
| fi | |
| # Success message | |
| echo -e "\n${GREEN}[SUCCESS] Setup complete!${NC}" | |
| echo -e "Restart your terminal or run: zsh" | |
| echo -e "Edit configuration: nano $zshrc" | |
| echo -e "Note: First launch may be slow while plugins compile" | |
| } | |
| # Execute main function | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment