Created
July 30, 2026 05:20
-
-
Save Aabayoumy/11c23c69ea3cc6027bf24ee9027cd336 to your computer and use it in GitHub Desktop.
Unified Debian/Ubuntu + Alma/RHEL VM bootstrap script
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
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # Optional override: TARGET_USER=myuser bash bootstrap.sh | |
| TARGET_USER="${TARGET_USER:-abayoumy}" | |
| if [ -r /etc/os-release ]; then | |
| . /etc/os-release | |
| else | |
| echo "Cannot detect OS: /etc/os-release not found" | |
| exit 1 | |
| fi | |
| if command -v apt-get >/dev/null 2>&1; then | |
| OS_FAMILY="debian" | |
| SUDO_GROUP="sudo" | |
| elif command -v dnf >/dev/null 2>&1; then | |
| OS_FAMILY="rhel" | |
| SUDO_GROUP="wheel" | |
| else | |
| echo "Unsupported distro. Supported: Debian/Ubuntu and Alma/RHEL-like systems." | |
| exit 1 | |
| fi | |
| # =========================================================== | |
| # Step 0: Ensure user exists and has passwordless sudo | |
| # =========================================================== | |
| if ! id -u "$TARGET_USER" >/dev/null 2>&1; then | |
| sudo useradd -m -s /bin/bash "$TARGET_USER" | |
| fi | |
| sudo usermod -aG "$SUDO_GROUP" "$TARGET_USER" || true | |
| echo "$TARGET_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee "/etc/sudoers.d/$TARGET_USER" >/dev/null | |
| sudo chmod 440 "/etc/sudoers.d/$TARGET_USER" | |
| # =========================================================== | |
| # Step 1: Backup existing configurations | |
| # =========================================================== | |
| if ! command -v zip &> /dev/null; then | |
| if [ "$OS_FAMILY" = "debian" ]; then | |
| sudo apt-get update -qq | |
| sudo apt-get install -y -qq zip | |
| else | |
| sudo dnf install -y zip | |
| fi | |
| fi | |
| BACKUP_DATE=$(date +"%Y-%m-%d_%H-%M-%S") | |
| BACKUP_FILE="$HOME/terminal_backup_$BACKUP_DATE.zip" | |
| zip -rq "$BACKUP_FILE" \ | |
| ~/.zshrc ~/.zprofile ~/.zsh_history ~/.oh-my-zsh \ | |
| ~/.config/nvim ~/.local/share/nvim ~/.local/state/nvim ~/.cache/nvim \ | |
| ~/.config/fastfetch ~/.config/starship.toml \ | |
| 2>/dev/null || true | |
| echo "Backup saved to: $BACKUP_FILE" | |
| # =========================================================== | |
| # Step 2: Clean existing config files | |
| # =========================================================== | |
| rm -rf ~/.config/nvim ~/.local/share/nvim ~/.local/state/nvim ~/.cache/nvim | |
| rm -rf ~/.config/fastfetch | |
| rm -rf ~/.oh-my-zsh | |
| rm -f ~/.zshrc ~/.zprofile ~/.zsh_history | |
| ARCH=$(uname -m) | |
| echo "Detected architecture: $ARCH" | |
| # =========================================================== | |
| # Step 3: Install core packages | |
| # =========================================================== | |
| echo "Installing core packages..." | |
| if [ "$OS_FAMILY" = "debian" ]; then | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| curl git wget gawk zsh fzf \ | |
| bat ripgrep fd-find build-essential \ | |
| unzip luarocks xclip qemu-guest-agent aria2 ca-certificates | |
| # Optional tools | |
| sudo apt-get install -y zoxide || true | |
| sudo apt-get install -y eza || sudo apt-get install -y exa || true | |
| else | |
| sudo dnf install -y epel-release dnf-plugins-core | |
| if command -v crb &> /dev/null; then | |
| sudo crb enable || true | |
| else | |
| sudo dnf config-manager --set-enabled crb || true | |
| fi | |
| sudo dnf makecache -y | |
| sudo dnf install -y \ | |
| curl git wget gawk zsh fzf \ | |
| bat ripgrep gcc gcc-c++ make \ | |
| unzip luarocks xclip qemu-guest-agent aria2 tar ca-certificates | |
| # Optional tools with distro naming differences | |
| sudo dnf install -y zoxide || true | |
| sudo dnf install -y eza || sudo dnf install -y exa || true | |
| sudo dnf install -y fd-find || sudo dnf install -y fd || true | |
| fi | |
| sudo systemctl enable --now qemu-guest-agent || true | |
| # fd-find installs as 'fdfind' on Debian/Ubuntu — symlink to expected name | |
| if command -v fdfind &> /dev/null && ! command -v fd &> /dev/null; then | |
| sudo ln -sf "$(which fdfind)" /usr/local/bin/fd | |
| fi | |
| # batcat → bat symlink on Debian/Ubuntu | |
| if command -v batcat &> /dev/null && ! command -v bat &> /dev/null; then | |
| sudo ln -sf "$(which batcat)" /usr/local/bin/bat | |
| fi | |
| # exa fallback when eza is unavailable | |
| if command -v exa &> /dev/null && ! command -v eza &> /dev/null; then | |
| sudo ln -sf "$(which exa)" /usr/local/bin/eza | |
| fi | |
| # =========================================================== | |
| # Step 4: Install latest Fastfetch | |
| # =========================================================== | |
| echo "Installing Fastfetch..." | |
| if [ "$ARCH" = "x86_64" ]; then | |
| FF_DEB="fastfetch-linux-amd64.deb" | |
| FF_RPM="fastfetch-linux-amd64.rpm" | |
| elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then | |
| FF_DEB="fastfetch-linux-aarch64.deb" | |
| FF_RPM="fastfetch-linux-aarch64.rpm" | |
| else | |
| echo "Unsupported architecture for fastfetch: $ARCH" | |
| exit 1 | |
| fi | |
| if [ "$OS_FAMILY" = "debian" ]; then | |
| aria2c -x 4 -s 4 -o "$FF_DEB" \ | |
| "https://github.com/fastfetch-cli/fastfetch/releases/latest/download/$FF_DEB" | |
| sudo apt-get install -y "./$FF_DEB" && rm "$FF_DEB" | |
| else | |
| aria2c -x 4 -s 4 -o "$FF_RPM" \ | |
| "https://github.com/fastfetch-cli/fastfetch/releases/latest/download/$FF_RPM" | |
| sudo dnf install -y "./$FF_RPM" && rm "$FF_RPM" | |
| fi | |
| # =========================================================== | |
| # Step 5: Remove any existing Neovim installation | |
| # =========================================================== | |
| echo "Removing existing Neovim..." | |
| if [ "$OS_FAMILY" = "debian" ]; then | |
| sudo apt-get purge -y neovim neovim-runtime || true | |
| sudo apt-get autoremove -y || true | |
| else | |
| sudo dnf remove -y neovim neovim-runtime || true | |
| fi | |
| if command -v snap &> /dev/null; then sudo snap remove neovim || true; fi | |
| if command -v flatpak &> /dev/null; then sudo flatpak uninstall -y org.neovim.nvim || true; fi | |
| sudo rm -f /usr/bin/nvim /usr/local/bin/nvim | |
| sudo rm -rf /opt/nvim-linux* /opt/nvim | |
| # =========================================================== | |
| # Step 6: Install latest stable Neovim from GitHub | |
| # =========================================================== | |
| echo "Installing Neovim..." | |
| if [ "$ARCH" = "x86_64" ]; then | |
| NVIM_URL="https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz" | |
| elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then | |
| NVIM_URL="https://github.com/neovim/neovim/releases/latest/download/nvim-linux-arm64.tar.gz" | |
| else | |
| echo "Unsupported architecture: $ARCH"; exit 1 | |
| fi | |
| NVIM_TAR="nvim-download.tar.gz" | |
| aria2c -x 4 -s 4 -o "$NVIM_TAR" "$NVIM_URL" | |
| sudo mkdir -p /opt/nvim | |
| sudo tar -C /opt/nvim --strip-components=1 -xzf "$NVIM_TAR" | |
| sudo ln -sf /opt/nvim/bin/nvim /usr/local/bin/nvim | |
| rm "$NVIM_TAR" | |
| # =========================================================== | |
| # Step 7: Install Starship + download personal config from gist | |
| # =========================================================== | |
| echo "Installing Starship..." | |
| curl -sS https://starship.rs/install.sh | sh -s -- --yes | |
| mkdir -p ~/.config | |
| curl -fsSL "https://gist.githubusercontent.com/Aabayoumy/0d9eaec0629bbaea0c2c318b058525c1/raw/3f9ac8c2edc61eb9531a70fe962964aab4afa8d1/starship.toml" \ | |
| -o ~/.config/starship.toml | |
| # =========================================================== | |
| # Step 8: Configure Fastfetch | |
| # =========================================================== | |
| echo "Configuring Fastfetch..." | |
| mkdir -p ~/.config/fastfetch | |
| cat << 'EOF' > ~/.config/fastfetch/config.jsonc | |
| { | |
| "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", | |
| "logo": { | |
| "type": "small", | |
| "padding": { "top": 1 } | |
| }, | |
| "display": { | |
| "separator": " ❯ ", | |
| "bar": { | |
| "char": { "elapsed": "■", "total": " " }, | |
| "width": 12 | |
| } | |
| }, | |
| "modules": [ | |
| "title", | |
| "os", | |
| { "type": "cpu", "format": "{1} ({4} cores)" }, | |
| { "type": "cpuusage", "key": "CPU ", "percent": { "type": 3 } }, | |
| { "type": "memory", "key": "Mem ", "percent": { "type": 3 } }, | |
| { "type": "disk", "key": "Disk", "percent": { "type": 3 } }, | |
| "break" | |
| ] | |
| } | |
| EOF | |
| # =========================================================== | |
| # Step 9: Download Catppuccin Mocha zsh-syntax-highlighting theme | |
| # =========================================================== | |
| echo "Downloading Catppuccin Mocha syntax highlight theme..." | |
| mkdir -p ~/.config | |
| curl -fsSL \ | |
| "https://raw.githubusercontent.com/catppuccin/zsh-syntax-highlighting/main/themes/catppuccin_mocha-zsh-syntax-highlighting.zsh" \ | |
| -o ~/.config/catppuccin_mocha-zsh-syntax-highlighting.zsh | |
| # =========================================================== | |
| # Step 10: Write .zshrc | |
| # =========================================================== | |
| echo "Writing .zshrc..." | |
| cat << 'ZSHRC' > ~/.zshrc | |
| # =========================================================== | |
| # ZINIT — plugin manager (auto-installs on first run) | |
| # =========================================================== | |
| ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git" | |
| if [ ! -d "$ZINIT_HOME" ]; then | |
| mkdir -p "$(dirname "$ZINIT_HOME")" | |
| git clone https://github.com/zdharma-continuum/zinit.git "$ZINIT_HOME" | |
| fi | |
| source "${ZINIT_HOME}/zinit.zsh" | |
| # =========================================================== | |
| # PLUGINS | |
| # =========================================================== | |
| # zsh-completions: use blockf so zinit registers the extra fpath entries | |
| # before compinit runs — this is what enables filename/command completions | |
| zinit light zsh-users/zsh-autosuggestions | |
| zinit light zsh-users/zsh-history-substring-search | |
| zinit ice blockf; zinit light zsh-users/zsh-completions | |
| # Catppuccin Mocha syntax highlight theme — must load before the plugin | |
| source ~/.config/catppuccin_mocha-zsh-syntax-highlighting.zsh | |
| zinit light zsh-users/zsh-syntax-highlighting | |
| # OMZ snippets | |
| zinit snippet OMZL::git.zsh | |
| zinit snippet OMZP::git | |
| zinit snippet OMZP::sudo | |
| zinit snippet OMZP::command-not-found | |
| # =========================================================== | |
| # COMPLETION ENGINE (compinit BEFORE fzf-tab) | |
| # =========================================================== | |
| autoload -Uz compinit | |
| # Refresh .zcompdump at most once per day for faster startup | |
| if [[ -n ~/.zcompdump(#qN.mh+24) ]]; then | |
| compinit | |
| else | |
| compinit -C | |
| fi | |
| zinit cdreplay -q | |
| # fzf-tab must load AFTER compinit — it replaces the completion menu | |
| zinit light Aloxaf/fzf-tab | |
| # Completion styling | |
| zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*' | |
| zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" | |
| zstyle ':completion:*' group-name '' | |
| zstyle ':completion:*:descriptions' format '%F{yellow}-- %d --%f' | |
| zstyle ':completion:*:warnings' format '%F{red}no matches%f' | |
| zstyle ':completion::complete:*' use-cache yes | |
| zstyle ':completion::complete:*' cache-path ~/.zcompcache | |
| zstyle ':completion:*' special-dirs true | |
| zstyle ':completion:*' menu no # fzf-tab takes over the menu | |
| # fzf-tab: previews | |
| if command -v eza &>/dev/null; then | |
| zstyle ':fzf-tab:complete:cd:*' fzf-preview 'eza --icons --group-directories-first --color=always $realpath' | |
| zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'eza --icons --group-directories-first --color=always $realpath' | |
| zstyle ':fzf-tab:complete:*:*' fzf-preview 'bat --color=always --style=numbers $realpath 2>/dev/null || eza --icons --color=always $realpath' | |
| else | |
| zstyle ':fzf-tab:complete:cd:*' fzf-preview 'ls -la --color=always $realpath' | |
| zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'ls -la --color=always $realpath' | |
| zstyle ':fzf-tab:complete:*:*' fzf-preview 'bat --color=always --style=numbers $realpath 2>/dev/null || ls -la --color=always $realpath' | |
| fi | |
| setopt AUTO_MENU COMPLETE_IN_WORD ALWAYS_TO_END AUTO_PARAM_SLASH NO_CASE_GLOB | |
| # =========================================================== | |
| # HISTORY | |
| # =========================================================== | |
| HISTFILE=~/.zsh_history | |
| HISTSIZE=50000 | |
| SAVEHIST=50000 | |
| HISTDUP=erase | |
| setopt APPEND_HISTORY INC_APPEND_HISTORY SHARE_HISTORY | |
| setopt HIST_IGNORE_SPACE HIST_IGNORE_ALL_DUPS HIST_SAVE_NO_DUPS | |
| setopt HIST_IGNORE_DUPS HIST_FIND_NO_DUPS HIST_REDUCE_BLANKS | |
| setopt HIST_VERIFY EXTENDED_HISTORY | |
| # =========================================================== | |
| # KEY BINDINGS | |
| # =========================================================== | |
| bindkey -e | |
| bindkey '^[[H' beginning-of-line | |
| bindkey '^[[F' end-of-line | |
| bindkey '^[[3~' delete-char | |
| bindkey '^[[1;5C' forward-word # Ctrl→ jump word | |
| bindkey '^[[1;5D' backward-word # Ctrl← jump word | |
| bindkey '^[c' kill-region | |
| # → accepts the current autosuggestion (same as macOS behaviour) | |
| bindkey '^[[C' forward-char | |
| # End key also accepts full autosuggestion | |
| bindkey '^[[F' end-of-line | |
| # Ctrl-Space accepts autosuggestion without moving cursor | |
| bindkey '^ ' autosuggest-accept | |
| # zsh-history-substring-search: ↑/↓ filters by typed prefix | |
| bindkey '\e[A' history-substring-search-up | |
| bindkey '\e[B' history-substring-search-down | |
| # =========================================================== | |
| # DIRECTORY NAVIGATION | |
| # =========================================================== | |
| setopt AUTO_CD AUTO_PUSHD PUSHD_IGNORE_DUPS PUSHD_SILENT | |
| # =========================================================== | |
| # MISC | |
| # =========================================================== | |
| setopt INTERACTIVE_COMMENTS CORRECT NO_BEEP MULTIOS | |
| # =========================================================== | |
| # FZF | |
| # =========================================================== | |
| eval "$(fzf --zsh)" | |
| export FZF_DEFAULT_OPTS=" | |
| --height 40% | |
| --layout=reverse | |
| --border=rounded | |
| --preview-window=right:50%:wrap | |
| --color=fg:#cdd6f4,bg:#1e1e2e,hl:#89b4fa | |
| --color=fg+:#cdd6f4,bg+:#313244,hl+:#89dceb | |
| --color=info:#cba6f7,prompt:#f38ba8,pointer:#f5c2e7 | |
| --color=marker:#a6e3a1,spinner:#f5c2e7,header:#94e2d5 | |
| " | |
| if command -v fd &> /dev/null; then | |
| export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git' | |
| export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" | |
| fi | |
| ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#585b70" | |
| ZSH_AUTOSUGGEST_STRATEGY=(history completion) | |
| HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND='fg=#1e1e2e,bg=#a6e3a1,bold' | |
| HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND='fg=#1e1e2e,bg=#f38ba8,bold' | |
| # =========================================================== | |
| # EXTERNAL TOOLS | |
| # =========================================================== | |
| eval "$(zoxide init zsh)" | |
| eval "$(starship init zsh)" | |
| # =========================================================== | |
| # ALIASES — Navigation | |
| # =========================================================== | |
| alias ..='cd ..' | |
| alias ...='cd ../..' | |
| alias ....='cd ../../..' | |
| alias ~='cd ~' | |
| alias -- -='cd -' | |
| # =========================================================== | |
| # ALIASES — ls / eza | |
| # =========================================================== | |
| if command -v eza &>/dev/null; then | |
| alias l='eza --icons --group --group-directories-first' | |
| alias ls='eza --icons --group --group-directories-first' | |
| alias la='eza --icons -la --all --long --group --group-directories-first --header --time-style long-iso' | |
| alias ll='eza --long --group --group-directories-first --icons --header --time-style long-iso' | |
| alias lla='eza -lha --icons --git --group-directories-first --header --time-style long-iso' | |
| alias lt='eza --icons -T -L=1' | |
| alias llt='eza --tree --level=3 --icons --long' | |
| alias tree="eza --tree --all --ignore-glob='*.o|*.log' --git" | |
| else | |
| alias l='ls -CF --color=auto' | |
| alias ls='ls --color=auto' | |
| alias la='ls -la --color=auto' | |
| alias ll='ls -lh --color=auto' | |
| alias lla='ls -lha --color=auto' | |
| alias lt='ls -la --color=auto' | |
| alias llt='ls -la --color=auto' | |
| alias tree='find . -maxdepth 3 -print' | |
| fi | |
| # =========================================================== | |
| # ALIASES — cat / bat | |
| # =========================================================== | |
| alias cat='bat --paging=never' | |
| alias catp='bat' | |
| # =========================================================== | |
| # ALIASES — Editor | |
| # =========================================================== | |
| alias v='nvim' | |
| alias vi='nvim' | |
| alias vim='nvim' | |
| alias nv='nvim' | |
| alias svim='sudo nvim' | |
| alias vz='nvim ~/.zshrc' | |
| alias sz='source ~/.zshrc' | |
| # =========================================================== | |
| # ALIASES — Git | |
| # =========================================================== | |
| alias g='git' | |
| alias gs='git status -sb' | |
| alias gaa='git add .' | |
| alias gc='git commit -m' | |
| alias gca='git commit --amend --no-edit' | |
| alias gp='git push' | |
| alias gpf='git push --force-with-lease' | |
| alias gl='git pull' | |
| alias glog='git log --oneline --graph --decorate --all' | |
| alias gd='git diff' | |
| alias gds='git diff --staged' | |
| alias gcb='git checkout -b' | |
| alias gst='git stash' | |
| alias gstp='git stash pop' | |
| alias gri='git rebase -i' | |
| # =========================================================== | |
| # ALIASES — System / package manager | |
| # =========================================================== | |
| if command -v apt >/dev/null 2>&1; then | |
| alias update='sudo apt update && sudo apt upgrade -y' | |
| alias install='sudo apt install -y' | |
| alias remove='sudo apt remove -y' | |
| alias purge='sudo apt purge -y' | |
| alias autoremove='sudo apt autoremove -y' | |
| else | |
| alias update='sudo dnf upgrade --refresh -y' | |
| alias install='sudo dnf install -y' | |
| alias remove='sudo dnf remove -y' | |
| alias clean='sudo dnf autoremove -y && sudo dnf clean all' | |
| fi | |
| alias ports='ss -tulpn' | |
| alias psg='ps aux | grep' | |
| alias df='df -h' | |
| alias du='du -sh' | |
| alias free='free -h' | |
| alias top='htop 2>/dev/null || top' | |
| alias path='echo $PATH | tr ":" "\n"' | |
| alias myip='curl -s ifconfig.me' | |
| alias localip="ip -4 addr | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v 127" | |
| # =========================================================== | |
| # ALIASES — Safety | |
| # =========================================================== | |
| alias rm='rm -i' | |
| alias cp='cp -i' | |
| alias mv='mv -i' | |
| alias mkdir='mkdir -pv' | |
| # =========================================================== | |
| # ALIASES — Utilities | |
| # =========================================================== | |
| alias c='clear' | |
| alias cls='clear' | |
| alias q='exit' | |
| alias h='history | tail -50' | |
| alias hg='history | grep' | |
| alias reload='exec zsh' | |
| alias zshconfig='nvim ~/.zshrc' | |
| alias week='date +%V' | |
| alias timestamp='date +"%Y%m%d_%H%M%S"' | |
| alias rg='rg --smart-case --hidden' | |
| alias fd='fd -Lu' | |
| alias weather='curl v2.wttr.in' | |
| alias ff='clear && fastfetch' | |
| # =========================================================== | |
| # FUNCTIONS | |
| # =========================================================== | |
| # mkcd — mkdir + cd in one shot | |
| mkcd() { mkdir -p "$1" && cd "$1"; } | |
| # up N — go up N directories (e.g. up 3) | |
| up() { local p=""; for _ in $(seq 1 "${1:-1}"); do p+="../"; done; cd "$p"; } | |
| # extract — universal archive extractor | |
| extract() { | |
| if [ -f "$1" ]; then | |
| case "$1" in | |
| *.tar.bz2) tar xjf "$1" ;; | |
| *.tar.gz) tar xzf "$1" ;; | |
| *.tar.xz) tar xJf "$1" ;; | |
| *.tar.zst) tar --zstd -xf "$1" ;; | |
| *.bz2) bunzip2 "$1" ;; | |
| *.gz) gunzip "$1" ;; | |
| *.rar) unrar x "$1" ;; | |
| *.tar) tar xf "$1" ;; | |
| *.tbz2) tar xjf "$1" ;; | |
| *.tgz) tar xzf "$1" ;; | |
| *.zip) unzip "$1" ;; | |
| *.Z) uncompress "$1" ;; | |
| *.7z) 7z x "$1" ;; | |
| *) echo "'$1' cannot be extracted" ;; | |
| esac | |
| else | |
| echo "'$1' is not a valid file" | |
| fi | |
| } | |
| # bak — timestamped backup copy | |
| bak() { cp "$1" "$1.bak.$(date +%Y%m%d_%H%M%S)"; } | |
| # fcd — fuzzy-find a directory and cd into it | |
| fcd() { cd "$(find "${1:-.}" -type d 2>/dev/null | fzf)" || return; } | |
| # fe — fuzzy-find a file and open in nvim | |
| fe() { nvim "$(fzf --preview 'bat --color=always {}')"; } | |
| # =========================================================== | |
| # FASTFETCH — run on every new terminal | |
| # =========================================================== | |
| fastfetch | |
| ZSHRC | |
| # =========================================================== | |
| # Step 11: Install LazyVim | |
| # =========================================================== | |
| echo "Setting up LazyVim..." | |
| mkdir -p ~/.config/nvim | |
| git clone https://github.com/LazyVim/starter ~/.config/nvim | |
| rm -rf ~/.config/nvim/.git | |
| # =========================================================== | |
| # Step 12: Set Zsh as default shell | |
| # =========================================================== | |
| echo "Setting Zsh as default shell..." | |
| sudo chsh -s "$(which zsh)" "$TARGET_USER" | |
| echo "" | |
| echo "Done! Backup saved to: $BACKUP_FILE" | |
| echo "Run 'exec zsh' or open a new terminal to start." | |
| echo "(zinit will auto-install all plugins on first launch)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment