install.sh
20221 bytes
1#!/bin/sh
2#
3# This script should be run via curl:
4# sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
5# or via wget:
6# sh -c "$(wget -qO- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
7# or via fetch:
8# sh -c "$(fetch -o - https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
9#
10# As an alternative, you can first download the install script and run it afterwards:
11# wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh
12# sh install.sh
13#
14# You can tweak the install behavior by setting variables when running the script. For
15# example, to change the path to the Oh My Zsh repository:
16# ZSH=~/.zsh sh install.sh
17#
18# Respects the following environment variables:
19# ZDOTDIR - path to Zsh dotfiles directory (default: unset). See [1][2]
20# [1] https://zsh.sourceforge.io/Doc/Release/Parameters.html#index-ZDOTDIR
21# [2] https://zsh.sourceforge.io/Doc/Release/Files.html#index-ZDOTDIR_002c-use-of
22# ZSH - path to the Oh My Zsh repository folder (default: $HOME/.oh-my-zsh)
23# REPO - name of the GitHub repo to install from (default: ohmyzsh/ohmyzsh)
24# REMOTE - full remote URL of the git repo to install (default: GitHub via HTTPS)
25# BRANCH - branch to check out immediately after install (default: master)
26#
27# Other options:
28# CHSH - 'no' means the installer will not change the default shell (default: yes)
29# RUNZSH - 'no' means the installer will not run zsh after the install (default: yes)
30# KEEP_ZSHRC - 'yes' means the installer will not replace an existing .zshrc (default: no)
31# OVERWRITE_CONFIRMATION - 'no' means the installer will not ask for confirmation to overwrite the existing .zshrc (default: yes)
32#
33# You can also pass some arguments to the install script to set some these options:
34# --skip-chsh: has the same behavior as setting CHSH to 'no'
35# --unattended: sets both CHSH and RUNZSH to 'no'
36# --keep-zshrc: sets KEEP_ZSHRC to 'yes'
37# For example:
38# sh install.sh --unattended
39# or:
40# sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
41#
42set -e
43
44# Make sure important variables exist if not already defined
45#
46# $USER is defined by login(1) which is not always executed (e.g. containers)
47# POSIX: https://pubs.opengroup.org/onlinepubs/009695299/utilities/id.html
48USER=${USER:-$(id -u -n)}
49# $HOME is defined at the time of login, but it could be unset. If it is unset,
50# a tilde by itself (~) will not be expanded to the current user's home directory.
51# POSIX: https://pubs.opengroup.org/onlinepubs/009696899/basedefs/xbd_chap08.html#tag_08_03
52if [ -z "$HOME" ]; then
53 HOME=$(getent passwd "$USER" 2>/dev/null | cut -d: -f6)
54
55 # macOS does not have getent; fall back to tilde expansion, but only if
56 # $USER is a safe username. The eval below would otherwise expand any shell
57 # metacharacters in $USER and allow command injection (CWE-78).
58 case "$USER" in
59 *[![:alnum:]_.-]*|'')
60 ;;
61 *)
62 resolved_home=$(eval echo ~"$USER")
63 # Unknown users are not expanded and produce a literal "~username".
64 [ "$resolved_home" = "~$USER" ] || HOME=$resolved_home
65 ;;
66 esac
67
68 case "$HOME" in
69 /*) ;;
70 *)
71 echo "Error: unable to determine the current user's home directory." >&2
72 echo "Set HOME explicitly and rerun the installer." >&2
73 exit 1
74 ;;
75 esac
76fi
77
78
79# Track if $ZSH was provided
80custom_zsh=${ZSH:+yes}
81
82# Use $zdot to keep track of where the directory is for zsh dotfiles
83# To check if $ZDOTDIR was provided, explicitly check for $ZDOTDIR
84zdot="${ZDOTDIR:-$HOME}"
85
86# Default value for $ZSH
87# a) if $ZDOTDIR is supplied and not $HOME: $ZDOTDIR/ohmyzsh
88# b) otherwise, $HOME/.oh-my-zsh
89if [ -n "$ZDOTDIR" ] && [ "$ZDOTDIR" != "$HOME" ]; then
90 ZSH="${ZSH:-$ZDOTDIR/ohmyzsh}"
91fi
92ZSH="${ZSH:-$HOME/.oh-my-zsh}"
93
94# Default settings
95REPO=${REPO:-ohmyzsh/ohmyzsh}
96REMOTE=${REMOTE:-https://github.com/${REPO}.git}
97BRANCH=${BRANCH:-master}
98
99# Other options
100CHSH=${CHSH:-yes}
101RUNZSH=${RUNZSH:-yes}
102KEEP_ZSHRC=${KEEP_ZSHRC:-no}
103OVERWRITE_CONFIRMATION=${OVERWRITE_CONFIRMATION:-yes}
104
105
106command_exists() {
107 command -v "$@" >/dev/null 2>&1
108}
109
110user_can_sudo() {
111 # Check if sudo is installed
112 command_exists sudo || return 1
113 # Termux can't run sudo, so we can detect it and exit the function early.
114 case "$PREFIX" in
115 *com.termux*) return 1 ;;
116 esac
117 # The following command has 3 parts:
118 #
119 # 1. Run `sudo` with `-v`. Does the following:
120 # • with privilege: asks for a password immediately.
121 # • without privilege: exits with error code 1 and prints the message:
122 # Sorry, user <username> may not run sudo on <hostname>
123 #
124 # 2. Pass `-n` to `sudo` to tell it to not ask for a password. If the
125 # password is not required, the command will finish with exit code 0.
126 # If one is required, sudo will exit with error code 1 and print the
127 # message:
128 # sudo: a password is required
129 #
130 # 3. Check for the words "may not run sudo" in the output to really tell
131 # whether the user has privileges or not. For that we have to make sure
132 # to run `sudo` in the default locale (with `LANG=`) so that the message
133 # stays consistent regardless of the user's locale.
134 #
135 ! LANG= sudo -n -v 2>&1 | grep -q "may not run sudo"
136}
137
138# The [ -t 1 ] check only works when the function is not called from
139# a subshell (like in `$(...)` or `(...)`, so this hack redefines the
140# function at the top level to always return false when stdout is not
141# a tty.
142if [ -t 1 ]; then
143 is_tty() {
144 true
145 }
146else
147 is_tty() {
148 false
149 }
150fi
151
152# This function uses the logic from supports-hyperlinks[1][2], which is
153# made by Kat Marchán (@zkat) and licensed under the Apache License 2.0.
154# [1] https://github.com/zkat/supports-hyperlinks
155# [2] https://crates.io/crates/supports-hyperlinks
156#
157# Copyright (c) 2021 Kat Marchán
158#
159# Licensed under the Apache License, Version 2.0 (the "License");
160# you may not use this file except in compliance with the License.
161# You may obtain a copy of the License at
162#
163# http://www.apache.org/licenses/LICENSE-2.0
164#
165# Unless required by applicable law or agreed to in writing, software
166# distributed under the License is distributed on an "AS IS" BASIS,
167# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
168# See the License for the specific language governing permissions and
169# limitations under the License.
170supports_hyperlinks() {
171 # $FORCE_HYPERLINK must be set and be non-zero (this acts as a logic bypass)
172 if [ -n "$FORCE_HYPERLINK" ]; then
173 [ "$FORCE_HYPERLINK" != 0 ]
174 return $?
175 fi
176
177 # If stdout is not a tty, it doesn't support hyperlinks
178 is_tty || return 1
179
180 # DomTerm terminal emulator (domterm.org)
181 if [ -n "$DOMTERM" ]; then
182 return 0
183 fi
184
185 # VTE-based terminals above v0.50 (Gnome Terminal, Guake, ROXTerm, etc)
186 if [ -n "$VTE_VERSION" ]; then
187 [ $VTE_VERSION -ge 5000 ]
188 return $?
189 fi
190
191 # If $TERM_PROGRAM is set, these terminals support hyperlinks
192 case "$TERM_PROGRAM" in
193 ghostty|Hyper|iTerm.app|terminology|vscode|WezTerm) return 0 ;;
194 esac
195
196 # These termcap entries support hyperlinks
197 case "$TERM" in
198 alacritty|alacritty-direct|xterm-ghostty|xterm-kitty) return 0 ;;
199 esac
200
201 # xfce4-terminal supports hyperlinks
202 if [ "$COLORTERM" = "xfce4-terminal" ]; then
203 return 0
204 fi
205
206 # Windows Terminal also supports hyperlinks
207 if [ -n "$WT_SESSION" ]; then
208 return 0
209 fi
210
211 # Konsole supports hyperlinks, but it's an opt-in setting that can't be detected
212 # https://github.com/ohmyzsh/ohmyzsh/issues/10964
213 # if [ -n "$KONSOLE_VERSION" ]; then
214 # return 0
215 # fi
216
217 return 1
218}
219
220# Adapted from code and information by Anton Kochkov (@XVilka)
221# Source: https://gist.github.com/XVilka/8346728
222supports_truecolor() {
223 case "$COLORTERM" in
224 truecolor|24bit) return 0 ;;
225 esac
226
227 case "$TERM" in
228 iterm |\
229 tmux-truecolor |\
230 linux-truecolor |\
231 xterm-truecolor |\
232 screen-truecolor) return 0 ;;
233 esac
234
235 return 1
236}
237
238fmt_link() {
239 # $1: text, $2: url, $3: fallback mode
240 if supports_hyperlinks; then
241 printf '\033]8;;%s\033\\%s\033]8;;\033\\\n' "$2" "$1"
242 return
243 fi
244
245 case "$3" in
246 --text) printf '%s\n' "$1" ;;
247 --url|*) fmt_underline "$2" ;;
248 esac
249}
250
251fmt_underline() {
252 is_tty && printf '\033[4m%s\033[24m\n' "$*" || printf '%s\n' "$*"
253}
254
255# shellcheck disable=SC2016 # backtick in single-quote
256fmt_code() {
257 is_tty && printf '`\033[2m%s\033[22m`\n' "$*" || printf '`%s`\n' "$*"
258}
259
260fmt_error() {
261 printf '%sError: %s%s\n' "${FMT_BOLD}${FMT_RED}" "$*" "$FMT_RESET" >&2
262}
263
264setup_color() {
265 # Only use colors if connected to a terminal
266 if ! is_tty; then
267 FMT_RAINBOW=""
268 FMT_RED=""
269 FMT_GREEN=""
270 FMT_YELLOW=""
271 FMT_BLUE=""
272 FMT_BOLD=""
273 FMT_RESET=""
274 return
275 fi
276
277 if supports_truecolor; then
278 FMT_RAINBOW="
279 $(printf '\033[38;2;255;0;0m')
280 $(printf '\033[38;2;255;97;0m')
281 $(printf '\033[38;2;247;255;0m')
282 $(printf '\033[38;2;0;255;30m')
283 $(printf '\033[38;2;77;0;255m')
284 $(printf '\033[38;2;168;0;255m')
285 $(printf '\033[38;2;245;0;172m')
286 "
287 else
288 FMT_RAINBOW="
289 $(printf '\033[38;5;196m')
290 $(printf '\033[38;5;202m')
291 $(printf '\033[38;5;226m')
292 $(printf '\033[38;5;082m')
293 $(printf '\033[38;5;021m')
294 $(printf '\033[38;5;093m')
295 $(printf '\033[38;5;163m')
296 "
297 fi
298
299 FMT_RED=$(printf '\033[31m')
300 FMT_GREEN=$(printf '\033[32m')
301 FMT_YELLOW=$(printf '\033[33m')
302 FMT_BLUE=$(printf '\033[34m')
303 FMT_BOLD=$(printf '\033[1m')
304 FMT_RESET=$(printf '\033[0m')
305}
306
307setup_ohmyzsh() {
308 # Prevent the cloned repository from having insecure permissions. Failing to do
309 # so causes compinit() calls to fail with "command not found: compdef" errors
310 # for users with insecure umasks (e.g., "002", allowing group writability). Note
311 # that this will be ignored under Cygwin by default, as Windows ACLs take
312 # precedence over umasks except for filesystems mounted with option "noacl".
313 umask g-w,o-w
314
315 echo "${FMT_BLUE}Cloning Oh My Zsh...${FMT_RESET}"
316
317 command_exists git || {
318 fmt_error "git is not installed"
319 exit 1
320 }
321
322 ostype=$(uname)
323 if [ -z "${ostype%CYGWIN*}" ] && git --version | grep -Eq 'msysgit|windows'; then
324 fmt_error "Windows/MSYS Git is not supported on Cygwin"
325 fmt_error "Make sure the Cygwin git package is installed and is first on the \$PATH"
326 exit 1
327 fi
328
329 # Manual clone with git config options to support git < v1.7.2
330 git init --quiet "$ZSH" && cd "$ZSH" \
331 && git config core.eol lf \
332 && git config core.autocrlf false \
333 && git config fsck.zeroPaddedFilemode ignore \
334 && git config fetch.fsck.zeroPaddedFilemode ignore \
335 && git config receive.fsck.zeroPaddedFilemode ignore \
336 && git config oh-my-zsh.remote origin \
337 && git config oh-my-zsh.branch "$BRANCH" \
338 && git remote add origin "$REMOTE" \
339 && git fetch --depth=1 origin \
340 && git checkout -b "$BRANCH" "origin/$BRANCH" || {
341 [ ! -d "$ZSH" ] || {
342 cd -
343 rm -rf "$ZSH" 2>/dev/null
344 }
345 fmt_error "git clone of oh-my-zsh repo failed"
346 exit 1
347 }
348 # Exit installation directory
349 cd -
350
351 echo
352}
353
354setup_zshrc() {
355 # Keep most recent old .zshrc at .zshrc.pre-oh-my-zsh, and older ones
356 # with datestamp of installation that moved them aside, so we never actually
357 # destroy a user's original zshrc
358 echo "${FMT_BLUE}Looking for an existing zsh config...${FMT_RESET}"
359
360 # Must use this exact name so uninstall.sh can find it
361 OLD_ZSHRC="$zdot/.zshrc.pre-oh-my-zsh"
362 if [ -f "$zdot/.zshrc" ] || [ -h "$zdot/.zshrc" ]; then
363 # Skip this if the user doesn't want to replace an existing .zshrc
364 if [ "$KEEP_ZSHRC" = yes ]; then
365 echo "${FMT_YELLOW}Found ${zdot}/.zshrc.${FMT_RESET} ${FMT_GREEN}Keeping...${FMT_RESET}"
366 return
367 fi
368
369 if [ "$OVERWRITE_CONFIRMATION" != "no" ]; then
370 # Ask user for confirmation before backing up and overwriting
371 echo "${FMT_YELLOW}Found ${zdot}/.zshrc."
372 echo "The existing .zshrc will be backed up to .zshrc.pre-oh-my-zsh if overwritten."
373 echo "Make sure your .zshrc contains the following minimal configuration if you choose not to overwrite it:${FMT_RESET}"
374 echo "----------------------------------------"
375 cat "$ZSH/templates/minimal.zshrc"
376 echo "----------------------------------------"
377 printf '%sDo you want to overwrite it with the Oh My Zsh template? [Y/n]%s ' \
378 "$FMT_YELLOW" "$FMT_RESET"
379 read -r opt
380 case $opt in
381 [Yy]*|"") ;;
382 [Nn]*) echo "Overwrite skipped. Existing .zshrc will be kept."; return ;;
383 *) echo "Invalid choice. Overwrite skipped. Existing .zshrc will be kept."; return ;;
384 esac
385 fi
386
387 if [ -e "$OLD_ZSHRC" ]; then
388 OLD_OLD_ZSHRC="${OLD_ZSHRC}-$(date +%Y-%m-%d_%H-%M-%S)"
389 if [ -e "$OLD_OLD_ZSHRC" ]; then
390 fmt_error "$OLD_OLD_ZSHRC exists. Can't back up ${OLD_ZSHRC}"
391 fmt_error "re-run the installer again in a couple of seconds"
392 exit 1
393 fi
394 mv "$OLD_ZSHRC" "${OLD_OLD_ZSHRC}"
395
396 echo "${FMT_YELLOW}Found old .zshrc.pre-oh-my-zsh." \
397 "${FMT_GREEN}Backing up to ${OLD_OLD_ZSHRC}${FMT_RESET}"
398 fi
399 echo "${FMT_GREEN}Backing up to ${OLD_ZSHRC}${FMT_RESET}"
400 mv "$zdot/.zshrc" "$OLD_ZSHRC"
401 fi
402
403 echo "${FMT_GREEN}Using the Oh My Zsh template file and adding it to $zdot/.zshrc.${FMT_RESET}"
404
405 # Modify $ZSH variable in .zshrc directory to use the literal $ZDOTDIR or $HOME
406 omz="$ZSH"
407 if [ -n "$ZDOTDIR" ] && [ "$ZDOTDIR" != "$HOME" ]; then
408 omz=$(echo "$omz" | sed "s|^$ZDOTDIR/|\$ZDOTDIR/|")
409 fi
410 omz=$(echo "$omz" | sed "s|^$HOME/|\$HOME/|")
411
412 sed "s|^export ZSH=.*$|export ZSH=\"${omz}\"|" "$ZSH/templates/zshrc.zsh-template" > "$zdot/.zshrc-omztemp"
413 mv -f "$zdot/.zshrc-omztemp" "$zdot/.zshrc"
414
415 echo
416}
417
418setup_shell() {
419 # Skip setup if the user wants or stdin is closed (not running interactively).
420 if [ "$CHSH" = no ]; then
421 return
422 fi
423
424 # If this user's login shell is already "zsh", do not attempt to switch.
425 if [ "$(basename -- "$SHELL")" = "zsh" ]; then
426 return
427 fi
428
429 # If this platform doesn't provide a "chsh" command, bail out.
430 if ! command_exists chsh; then
431 cat <<EOF
432I can't change your shell automatically because this system does not have chsh.
433${FMT_BLUE}Please manually change your default shell to zsh${FMT_RESET}
434EOF
435 return
436 fi
437
438 echo "${FMT_BLUE}Time to change your default shell to zsh:${FMT_RESET}"
439
440 # Prompt for user choice on changing the default login shell
441 printf '%sDo you want to change your default shell to zsh? [Y/n]%s ' \
442 "$FMT_YELLOW" "$FMT_RESET"
443 read -r opt
444 case $opt in
445 [Yy]*|"") ;;
446 [Nn]*) echo "Shell change skipped."; return ;;
447 *) echo "Invalid choice. Shell change skipped."; return ;;
448 esac
449
450 # Check if we're running on Termux
451 case "$PREFIX" in
452 *com.termux*) termux=true; zsh=zsh ;;
453 *) termux=false ;;
454 esac
455
456 if [ "$termux" != true ]; then
457 # Test for the right location of the "shells" file
458 if [ -f /etc/shells ]; then
459 shells_file=/etc/shells
460 elif [ -f /usr/share/defaults/etc/shells ]; then # Solus OS
461 shells_file=/usr/share/defaults/etc/shells
462 else
463 fmt_error "could not find /etc/shells file. Change your default shell manually."
464 return
465 fi
466
467 # Get the path to the right zsh binary
468 # 1. Use the most preceding one based on $PATH, then check that it's in the shells file
469 # 2. If that fails, get a zsh path from the shells file, then check it actually exists
470 if ! zsh=$(command -v zsh) || ! grep -qx "$zsh" "$shells_file"; then
471 if ! zsh=$(grep '^/.*/zsh$' "$shells_file" | tail -n 1) || [ ! -f "$zsh" ]; then
472 fmt_error "no zsh binary found or not present in '$shells_file'"
473 fmt_error "change your default shell manually."
474 return
475 fi
476 fi
477 fi
478
479 # We're going to change the default shell, so back up the current one
480 if [ -n "$SHELL" ]; then
481 echo "$SHELL" > "$zdot/.shell.pre-oh-my-zsh"
482 else
483 grep "^$USER:" /etc/passwd | awk -F: '{print $7}' > "$zdot/.shell.pre-oh-my-zsh"
484 fi
485
486 echo "Changing your shell to $zsh..."
487
488 # Check if user has sudo privileges to run `chsh` with or without `sudo`
489 #
490 # This allows the call to succeed without password on systems where the
491 # user does not have a password but does have sudo privileges, like in
492 # Google Cloud Shell.
493 #
494 # On systems that don't have a user with passwordless sudo, the user will
495 # be prompted for the password either way, so this shouldn't cause any issues.
496 #
497 if user_can_sudo; then
498 sudo -k >/dev/null 2>&1 || true # -k forces the password prompt when supported
499 sudo chsh -s "$zsh" "$USER"
500 chsh_status=$?
501 else
502 chsh -s "$zsh" "$USER" # run chsh normally
503 chsh_status=$?
504 fi
505
506 # Check if the shell change was successful
507 if [ "$chsh_status" -ne 0 ]; then
508 fmt_error "chsh command unsuccessful. Change your default shell manually."
509 else
510 export SHELL="$zsh"
511 echo "${FMT_GREEN}Shell successfully changed to '$zsh'.${FMT_RESET}"
512 fi
513
514 echo
515}
516
517# shellcheck disable=SC2183 # printf string has more %s than arguments ($FMT_RAINBOW expands to multiple arguments)
518print_success() {
519 printf '%s %s__ %s %s %s %s %s__ %s\n' $FMT_RAINBOW $FMT_RESET
520 printf '%s ____ %s/ /_ %s ____ ___ %s__ __ %s ____ %s_____%s/ /_ %s\n' $FMT_RAINBOW $FMT_RESET
521 printf '%s / __ \\%s/ __ \\ %s / __ `__ \\%s/ / / / %s /_ / %s/ ___/%s __ \\ %s\n' $FMT_RAINBOW $FMT_RESET
522 printf '%s/ /_/ /%s / / / %s / / / / / /%s /_/ / %s / /_%s(__ )%s / / / %s\n' $FMT_RAINBOW $FMT_RESET
523 printf '%s\\____/%s_/ /_/ %s /_/ /_/ /_/%s\\__, / %s /___/%s____/%s_/ /_/ %s\n' $FMT_RAINBOW $FMT_RESET
524 printf '%s %s %s %s /____/ %s %s %s %s....is now installed!%s\n' $FMT_RAINBOW $FMT_GREEN $FMT_RESET
525 printf '\n'
526 printf '\n'
527 printf "%s %s %s\n" "Before you scream ${FMT_BOLD}${FMT_YELLOW}Oh My Zsh!${FMT_RESET} look over the" \
528 "$(fmt_code "$(fmt_link ".zshrc" "file://$zdot/.zshrc" --text)")" \
529 "file to select plugins, themes, and options."
530 printf '\n'
531 printf '%s\n' "• Follow us on X: $(fmt_link @ohmyzsh https://x.com/ohmyzsh)"
532 printf '%s\n' "• Join our Discord community: $(fmt_link "Discord server" https://discord.gg/ohmyzsh)"
533 printf '%s\n' "• Get stickers, t-shirts, coffee mugs and more: $(fmt_link "CommitGoods Shop" https://commitgoods.com/collections/oh-my-zsh)"
534 printf '%s\n' $FMT_RESET
535}
536
537main() {
538 # Run as unattended if stdin is not a tty
539 if [ ! -t 0 ]; then
540 RUNZSH=no
541 CHSH=no
542 OVERWRITE_CONFIRMATION=no
543 fi
544
545 # Parse arguments
546 while [ $# -gt 0 ]; do
547 case $1 in
548 --unattended) RUNZSH=no; CHSH=no; OVERWRITE_CONFIRMATION=no ;;
549 --skip-chsh) CHSH=no ;;
550 --keep-zshrc) KEEP_ZSHRC=yes ;;
551 esac
552 shift
553 done
554
555 setup_color
556
557 if ! command_exists zsh; then
558 echo "${FMT_YELLOW}Zsh is not installed.${FMT_RESET} Please install zsh first."
559 exit 1
560 fi
561
562 if [ -d "$ZSH" ]; then
563 echo "${FMT_YELLOW}The \$ZSH folder already exists ($ZSH).${FMT_RESET}"
564 if [ "$custom_zsh" = yes ]; then
565 cat <<EOF
566
567You ran the installer with the \$ZSH setting or the \$ZSH variable is
568exported. You have 3 options:
569
5701. Unset the ZSH variable when calling the installer:
571 $(fmt_code "ZSH= sh install.sh")
5722. Install Oh My Zsh to a directory that doesn't exist yet:
573 $(fmt_code "ZSH=path/to/new/ohmyzsh/folder sh install.sh")
5743. (Caution) If the folder doesn't contain important information,
575 you can just remove it with $(fmt_code "rm -r $ZSH")
576
577EOF
578 else
579 echo "You'll need to remove it if you want to reinstall."
580 fi
581 exit 1
582 fi
583
584 # Create ZDOTDIR folder structure if it doesn't exist
585 if [ -n "$ZDOTDIR" ]; then
586 mkdir -p "$ZDOTDIR"
587 fi
588
589 setup_ohmyzsh
590 setup_zshrc
591 setup_shell
592
593 print_success
594
595 if [ $RUNZSH = no ]; then
596 echo "${FMT_YELLOW}Run zsh to try it out.${FMT_RESET}"
597 exit
598 fi
599
600 exec zsh -l
601}
602
603main "$@"