最終更新 2 weeks ago

Cross-platform Zsh setup scripts and managed dotfiles with Oh My Zsh framework, Starship prompt, aliases, functions, and path configuration.

修正履歴 230a0249b29a40b5f30bf3c8280571399b776f76

README.md Raw

Bash Script Installer for Zsh

The "Bash Script Installer" simplifies the setup of Zsh.

Zsh

Ubuntu

bash -c "$(curl -fsSL https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD/zsh_ubuntu.sh)"

MacOS

bash -c "$(curl -fsSL https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD/zsh_macos.sh)"
zsh_macos.sh Raw
1#!/bin/bash
2set -euo pipefail
3
4# =============================
5# COLORS & LOGGING
6# =============================
7RED='\033[0;31m'
8GREEN='\033[0;32m'
9YELLOW='\033[1;33m'
10BLUE='\033[0;34m'
11NC='\033[0m'
12
13log() { echo -e "${BLUE}[INFO]${NC} $*"; }
14ok() { echo -e "${GREEN}[OK]${NC} $*"; }
15warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
16err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
17
18# =============================
19# CONFIG
20# =============================
21CONFIG_FILES=(
22 ".alias|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/alias"
23 ".func|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/func"
24 ".pathrc|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/pathrc"
25 ".sourcerc|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/sourcerc"
26 ".vimrc|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/vimrc"
27 ".zshrc|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/zshrc"
28)
29
30# =============================
31# REQUIREMENTS
32# =============================
33check_requirements() {
34 if [[ $EUID -eq 0 ]]; then
35 err "Do not run as root on macOS"
36 exit 1
37 fi
38}
39
40# =============================
41# INSTALLATION FUNCTIONS
42# =============================
43configure_git() {
44 log "Configuring Git..."
45 read -p "Git name (leave empty to skip): " name
46 read -p "Git email (leave empty to skip): " email
47
48 if [[ -n "$name" ]]; then
49 git config --global user.name "$name"
50 fi
51 if [[ -n "$email" ]]; then
52 git config --global user.email "$email"
53 fi
54 ok "Git configured"
55}
56
57install_oh_my_zsh() {
58 if [[ -d "$HOME/.oh-my-zsh" ]]; then
59 ok "Oh My Zsh already installed"
60 return
61 fi
62
63 log "Installing Oh My Zsh..."
64 RUNZSH=no CHSH=no KEEP_ZSHRC=yes \
65 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
66 ok "Oh My Zsh installed"
67}
68
69install_plugins() {
70 log "Installing plugins..."
71 local dir="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins"
72 [[ -d "$dir/zsh-autosuggestions" ]] || git clone https://github.com/zsh-users/zsh-autosuggestions "$dir/zsh-autosuggestions"
73 [[ -d "$dir/zsh-syntax-highlighting" ]] || git clone https://github.com/zsh-users/zsh-syntax-highlighting "$dir/zsh-syntax-highlighting"
74 ok "Plugins installed"
75}
76
77install_theme() {
78 log "Installing Spaceship theme..."
79 local themes="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes"
80 local dir="$themes/spaceship-prompt"
81 [[ -d "$dir" ]] || git clone https://github.com/spaceship-prompt/spaceship-prompt.git "$dir" --depth=1
82 ln -sf "$dir/spaceship.zsh-theme" "$themes/spaceship.zsh-theme"
83 ok "Theme installed"
84}
85
86clean_macos_aliases() {
87 local alias_file="$HOME/.alias"
88 if [[ -f "$alias_file" ]]; then
89 log "Patching .alias for macOS (removing apt-get and xclip blocks)..."
90
91 # Delete the multiline apt-get block (from the comment down to the final command)
92 sed -i '' '/# System update & cleanup/,/sudo apt-get clean/d' "$alias_file"
93
94 # Delete the xclip block
95 sed -i '' '/# xclip shortcuts/,/xclip -selection clipboard/d' "$alias_file"
96
97 ok "macOS incompatibilities removed from .alias"
98 fi
99}
100
101download_configs() {
102 log "Downloading custom config files..."
103 local backup="$HOME/.config_backup_$(date +%Y%m%d_%H%M%S)"
104 mkdir -p "$backup"
105
106 for entry in "${CONFIG_FILES[@]}"; do
107 local f="${entry%%|*}"
108 local url="${entry##*|}"
109
110 if [[ -f "$HOME/$f" ]]; then
111 cp "$HOME/$f" "$backup/"
112 fi
113 log "Fetching $f ..."
114 curl -fsSL "$url" -o "$HOME/$f" || warn "Failed to download $f"
115 done
116
117 # Automatically clean up the macOS incompatible aliases after downloading
118 clean_macos_aliases
119
120 ok "Configs downloaded (Backup at $backup)"
121}
122
123update_zshrc() {
124 local zshrc="$HOME/.zshrc"
125 log "Updating .zshrc..."
126
127 if [[ ! -f "$zshrc" ]]; then
128 warn ".zshrc not found, creating new one..."
129 touch "$zshrc"
130 fi
131
132 # macOS BSD sed requires '-i ''' for in-place editing
133 grep -q 'ZSH_THEME="spaceship"' "$zshrc" || sed -i '' 's/ZSH_THEME=".*"/ZSH_THEME="spaceship"/' "$zshrc"
134 grep -q 'zsh-autosuggestions' "$zshrc" || sed -i '' 's/plugins=(/plugins=(zsh-autosuggestions /' "$zshrc"
135 grep -q 'zsh-syntax-highlighting' "$zshrc" || sed -i '' 's/plugins=(/plugins=(zsh-syntax-highlighting /' "$zshrc"
136 ok ".zshrc updated with plugins and theme"
137}
138
139switch_shell() {
140 log "Starting Zsh session..."
141 echo -e "${YELLOW}Type 'exit' to return to this installer menu.${NC}"
142 echo "----------------------------------------"
143 zsh -l
144 echo "----------------------------------------"
145 ok "Returned from Zsh session"
146}
147
148# =============================
149# INTERACTIVE MENU
150# =============================
151show_menu() {
152 echo "==========================================="
153 echo "macOS Zsh Setup - Choose what to do"
154 echo "==========================================="
155 echo " 0) Run ALL steps (1-7)"
156 echo " 1) Configure Git"
157 echo " 2) Install Oh My Zsh"
158 echo " 3) Install plugins (autosuggestions, syntax highlighting)"
159 echo " 4) Install Spaceship theme"
160 echo " 5) Download custom configs (~/.alias, .vimrc, etc.)"
161 echo " 6) Update ~/.zshrc for plugins & theme"
162 echo " 7) Switch to Zsh (Temporary Sub-shell)"
163 echo " 8) Quit"
164 echo "==========================================="
165 echo "Inputs: '0' (All), '1 3 4' (Specific), '0 !1 !5' (All except 1 and 5)"
166}
167
168run_choices() {
169 local input
170 read -p "Select: " input
171 input="${input//,/ }" # replace commas with spaces if used
172
173 local -a to_run=()
174 local -a to_exclude=()
175
176 # Parse positive selections and negative exclusions
177 for item in $input; do
178 if [[ "$item" == !* ]]; then
179 to_exclude+=("${item:1}") # Strip the '!' character
180 elif [[ "$item" == "0" ]]; then
181 to_run+=(1 2 3 4 5 6 7)
182 else
183 to_run+=("$item")
184 fi
185 done
186
187 # Protect against empty arrays crashing older bash versions with 'set -u'
188 if [[ ${#to_run[@]} -gt 0 ]]; then
189 for choice in "${to_run[@]}"; do
190
191 local skip=false
192 if [[ ${#to_exclude[@]} -gt 0 ]]; then
193 for ex in "${to_exclude[@]}"; do
194 if [[ "$choice" == "$ex" ]]; then
195 skip=true
196 break
197 fi
198 done
199 fi
200
201 $skip && continue
202
203 case "$choice" in
204 1) configure_git ;;
205 2) install_oh_my_
zsh_ubuntu.sh Raw
1#!/bin/bash
2set -euo pipefail
3
4# =============================
5# COLORS & LOGGING
6# =============================
7RED='\033[0;31m'
8GREEN='\033[0;32m'
9YELLOW='\033[1;33m'
10BLUE='\033[0;34m'
11NC='\033[0m'
12
13log() { echo -e "${BLUE}[INFO]${NC} $*"; }
14ok() { echo -e "${GREEN}[OK]${NC} $*"; }
15warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
16err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
17
18# =============================
19# FLAGS & CONFIG
20# =============================
21SKIP_PACKAGES=false
22SKIP_GIT_CONFIG=false
23SKIP_SHELL_CHANGE=false
24CUSTOM_CONFIG=false
25SKIP_XCLIP=false
26INSTALL_HOMEBREW=false
27
28declare -A CONFIG_FILES=(
29 [".alias"]="https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/alias"
30 [".func"]="https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/func"
31 [".pathrc"]="https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/pathrc"
32 [".sourcerc"]="https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/sourcerc"
33 [".vimrc"]="https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/vimrc"
34 [".zshrc"]="https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/zshrc"
35)
36
37# =============================
38# OS DETECTION
39# =============================
40detect_os() {
41 if [ -f /etc/os-release ]; then
42 . /etc/os-release
43 echo "$ID"
44 else
45 echo "unknown"
46 fi
47}
48
49# =============================
50# REQUIREMENTS
51# =============================
52check_requirements() {
53 # Fixed to prevent silent failure with 'set -e'
54 if [[ $EUID -eq 0 ]]; then
55 err "Do not run as root"
56 exit 1
57 fi
58 if ! command -v sudo >/dev/null; then
59 err "sudo required"
60 exit 1
61 fi
62}
63
64# =============================
65# INSTALLATION FUNCTIONS
66# =============================
67update_system() {
68 $SKIP_PACKAGES && return
69 log "Updating system..."
70 sudo apt-get update -y
71 sudo apt-get upgrade -y
72 ok "System updated"
73}
74
75install_packages() {
76 $SKIP_PACKAGES && return
77 log "Installing core packages..."
78 sudo apt-get install -y \
79 zsh git vim curl wget unzip zip build-essential xz-utils
80 ok "Packages installed"
81}
82
83set_timezone() {
84 log "Setting timezone to Asia/Singapore..."
85 sudo timedatectl set-timezone Asia/Singapore
86 ok "Timezone set to Asia/Singapore"
87}
88
89install_xclip() {
90 local os
91 os=$(detect_os)
92 [[ "$os" != "ubuntu" && "$os" != "debian" ]] && return 0
93 $SKIP_XCLIP && return 0
94 command -v xclip >/dev/null && ok "xclip already installed" && return 0
95
96 read -r -p "Install xclip? (y/N): " r
97 case "$r" in
98 [Yy]) sudo apt-get install -y xclip; ok "xclip installed" ;;
99 *) log "Skipping xclip installation" ;;
100 esac
101}
102
103configure_git() {
104 $SKIP_GIT_CONFIG && return
105 log "Configuring Git..."
106 read -p "Git name (leave empty to skip): " name
107 read -p "Git email (leave empty to skip): " email
108 [[ -n "$name" ]] && git config --global user.name "$name"
109 [[ -n "$email" ]] && git config --global user.email "$email"
110 ok "Git configured"
111}
112
113install_homebrew() {
114 ! $INSTALL_HOMEBREW && return
115 command -v brew >/dev/null && ok "Homebrew already installed" && return
116 log "Installing Homebrew..."
117 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
118 ok "Homebrew installed"
119}
120
121configure_shell() {
122 $SKIP_SHELL_CHANGE && return
123 log "Changing default shell to zsh..."
124 local zsh_path
125 zsh_path=$(command -v zsh)
126 grep -qx "$zsh_path" /etc/shells || echo "$zsh_path" | sudo tee -a /etc/shells >/dev/null
127 sudo chsh -s "$zsh_path" "$USER"
128 ok "Shell changed (requires logout/login to take effect)"
129}
130
131install_oh_my_zsh() {
132 [[ -d "$HOME/.oh-my-zsh" ]] && ok "Oh My Zsh already installed" && return
133 log "Installing Oh My Zsh..."
134 # Keep zshrc ensures we don't blow away configs if they exist
135 RUNZSH=no CHSH=no KEEP_ZSHRC=yes \
136 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
137 ok "Oh My Zsh installed"
138}
139
140install_plugins() {
141 log "Installing plugins..."
142 local dir="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins"
143 [[ -d "$dir/zsh-autosuggestions" ]] || git clone https://github.com/zsh-users/zsh-autosuggestions "$dir/zsh-autosuggestions"
144 [[ -d "$dir/zsh-syntax-highlighting" ]] || git clone https://github.com/zsh-users/zsh-syntax-highlighting "$dir/zsh-syntax-highlighting"
145 ok "Plugins installed"
146}
147
148install_theme() {
149 log "Installing Spaceship theme..."
150 local themes="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes"
151 local dir="$themes/spaceship-prompt"
152 [[ -d "$dir" ]] || git clone https://github.com/spaceship-prompt/spaceship-prompt.git "$dir" --depth=1
153 ln -sf "$dir/spaceship.zsh-theme" "$themes/spaceship.zsh-theme"
154 ok "Theme installed"
155}
156
157download_configs() {
158 log "Downloading custom config files..."
159 local backup="$HOME/.config_backup_$(date +%Y%m%d_%H%M%S)"
160 mkdir -p "$backup"
161 for f in "${!CONFIG_FILES[@]}"; do
162 if [[ -f "$HOME/$f" ]]; then
163 cp "$HOME/$f" "$backup/"
164 fi
165 log "Fetching $f ..."
166 curl -fsSL "${CONFIG_FILES[$f]}" -o "$HOME/$f" || warn "Failed to download $f"
167 done
168 ok "Configs downloaded (Backup at $backup)"
169}
170
171update_zshrc() {
172 local zshrc="$HOME/.zshrc"
173 log "Updating .zshrc..."
174
175 # Create zshrc if missing to prevent errors
176 if [[ ! -f "$zshrc" ]]; then
177 warn ".zshrc not found, creating new one..."
178 touch "$zshrc"
179 fi
180
181 # Use || true to prevent 'set -e' from exiting if grep finds nothing
182 grep -q 'ZSH_THEME="spaceship"' "$zshrc" || sed -i 's/ZSH_THEME=".*"/ZSH_THEME="spaceship"/' "$zshrc"
183 grep -q 'zsh-autosuggestions' "$zshrc" || sed -i 's/plugins=(/plugins=(zsh-autosuggestions /' "$zshrc"
184 grep -q 'zsh-syntax-highlighting' "$zshrc" || sed -i 's/plugins=(/plugins=(zsh-syntax-highlighting /' "$zshrc"
185 ok ".zshrc updated with plugins and theme"
186}
187
188switch_shell() {
189 $SKIP_SHELL_CHANGE && return
190
191 log "Starting Zsh session..."
192 echo -e "${YELLOW}Type 'exit' to return to this installer menu.${NC}"
193 echo "----------------------------------------"
194
195 # Run zsh as a subprocess, not exec
196 zsh -l
197
198 echo "----------------------------------------"
199 ok "Returned from Zsh session"
200}
201
202# =============================
203# INTERACTIVE MENU
204# =============================
205show_menu() {
206 echo "==========================================="
207 echo "Zsh Installer - Choose what to do"
208 echo "==========================================="
209 echo " 0) Run ALL steps (1-13)"
210 echo " 1) Update system packages"
211 echo " 2) Install core packages (zsh, git, vim, etc.)"
212 echo " 3) Set Timezone (Asia/Singapore)"
213 echo " 4) Install xclip"
214 echo " 5) Configure Git"
215 echo " 6) Install Homebrew"
216 echo " 7) Configure shell (chsh - sets default shell)"
217 echo " 8) Install Oh My Zsh"
218 echo " 9) Install plugins (autosuggestions, syntax highlighting)"
219 echo "10) Install Spaceship theme"
220 echo "11) Download custom configs (~/.alias, .vimrc, etc.)"
221 echo "12) Update ~/.zshrc for plugins & theme"
222 echo "13) Switch to Zsh (Temporary Sub-shell)"
223 echo "14) Quit"
224 echo "==========================================="
225 echo "Inputs: '0' (All), '2 3 7' (Specific), '0 !4 !6' (All except 4 and 6)"
226}
227
228run_choices() {
229 local input
230 read -p "Select: " input
231 input="${input//,/ }" # replace commas with spaces
232
233 local -a to_run=()
234 local -a to_exclude=()
235
236 # Parse positive selections and negative exclusions
237 for item in $input; do
238 if [[ "$item" == !* ]]; then
239 to_exclude+=("${item:1}") # Strip the '!' character
240 elif [[ "$item" == "0" ]]; then
241 to_run+=(1 2 3 4 5 6 7 8 9 10 11 12 13)
242 else
243 to_run+=("$item")
244 fi
245 done
246
247 # Loop through intended runs and apply exclusions
248 for choice in "${to_run[@]}"; do
249
250 local skip=false
251 for ex in "${to_exclude[@]}"; do
252 if [[ "$choice" == "$ex" ]]; then
253 skip=true
254 break
255 fi
256 done
257
258 $skip && continue
259
260 case "$choice" in
261 1) update_system ;;
262 2) install_packages ;;
263 3) set_timezone ;;
264 4) install_xclip ;;
265 5) configure_git ;;
266 6) install_homebrew ;;
267 7) configure_shell ;;
268 8) install_oh_my_zsh ;;
269 9) install_plugins ;;
270 10) install_theme ;;
271 11) download_configs ;;
272 12) update_zshrc ;;
273 13) switch_shell ;;
274 14) log "Exiting..."; exit 0 ;;
275 *) warn "Skipping invalid option: $choice" ;;
276 esac
277 echo
278 done
279}
280
281# =============================
282# MAIN
283# =============================
284main() {
285 check_requirements
286 while true; do
287 show_menu
288 run_choices
289 read -p "Do you want to run more options? (y/n): " again
290 [[ "$again" =~ ^[Yy]$ ]] || break
291 done
292 ok "Zsh installation/configuration complete!"
293}
294
295main "$@"