fix the silent death after installing zsh
Reported from a fresh Hetzner VPS: the run stopped dead right after apt finished installing zsh, printing nothing at all — just install.sh's "machine setup did not finish". install_oh_my_zsh carried a comment saying it "Returns 0 whatever happens". It did not. Under `set -e` a failing command inside a function aborts the SHELL at that line when the function is called plainly; `return 0` underneath is never reached. The command is also `>/dev/null 2>&1`, so the cause was invisible — which is why the transcript just ends. `|| true` is what actually makes it non-fatal. The file already uses that idiom correctly in four other places, so this was a slip rather than a misunderstanding. set_login_shell had the identical bug on `chsh`, which the same run would have hit on the very next question. Fixed differently and deliberately: `|| true` there would let the caller announce a login shell that was never set, so it returns chsh's real status and the CALLER guards the call — which is also what keeps set -e out of it. A refusal now reports, names the manual chsh command, and carries on, because a machine with zsh installed and bash at login still works. Does not explain WHY oh-my-zsh failed on that host — the output was discarded. It will now say "oh-my-zsh did not install" and continue, which is enough to see it. Verified: bash -n on both files, and a reduced case proving broken() exits 1 while fixed() survives. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -92,27 +92,36 @@ oh_my_zsh_installed() { [[ -d "${USER_HOME}/.oh-my-zsh" ]]; }
|
||||
install_oh_my_zsh() {
|
||||
# The installer refuses to run unattended over an existing install, so this is
|
||||
# only ever called when there is none.
|
||||
#
|
||||
# ── `|| true` is what makes this non-fatal, NOT the `return 0` below ──
|
||||
#
|
||||
# It used to be `return 0` alone, with a comment claiming the function returned
|
||||
# zero whatever happened. It did not. Under `set -e` a failing command inside a
|
||||
# function aborts the SHELL at that line when the function is called plainly —
|
||||
# `return 0` is never reached. So a machine where this curl or the installer
|
||||
# failed died here, silently, because the output is redirected: the run just
|
||||
# stopped after apt finished installing zsh, with nothing said. Observed on a
|
||||
# fresh Hetzner VPS, 2026-08-14.
|
||||
sudo -H -u "$USERNAME" sh -c \
|
||||
"$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended >/dev/null 2>&1
|
||||
# Returns 0 whatever happens. This is an optional improvement, and a
|
||||
# function that ends on a failing command is fatal under `set -e` when it
|
||||
# is called as a plain command — which would abort the remaining sections
|
||||
# over something the run could simply report. The caller checks the outcome.
|
||||
"$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended >/dev/null 2>&1 ||
|
||||
true
|
||||
# Belt and braces: `|| true` above already makes the last command succeed, and
|
||||
# this states the contract for anyone adding a line beneath it.
|
||||
return 0
|
||||
}
|
||||
|
||||
# `chsh` is what actually changes the login shell. Asked separately from
|
||||
# installing zsh, because having a shell available and being handed it at every
|
||||
# login are different decisions.
|
||||
# Reports whether chsh worked, rather than swallowing it. The same `set -e` trap as
|
||||
# install_oh_my_zsh applies — a bare `chsh` that fails kills the run at this line —
|
||||
# but here the answer matters: the caller announces the new login shell, and `|| true`
|
||||
# would have it announce one that was never set. So the status comes back and the
|
||||
# CALLER guards the call, which is also what keeps set -e out of it.
|
||||
set_login_shell() {
|
||||
local shell="$1"
|
||||
grep -qxF "$shell" /etc/shells || echo "$shell" >>/etc/shells
|
||||
chsh -s "$shell" "$USERNAME"
|
||||
# Returns 0 whatever happens. This is an optional improvement, and a
|
||||
# function that ends on a failing command is fatal under `set -e` when it
|
||||
# is called as a plain command — which would abort the remaining sections
|
||||
# over something the run could simply report. The caller checks the outcome.
|
||||
return 0
|
||||
chsh -s "$shell" "$USERNAME" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user