Here's a short shell script to quickly update a Mac OS-based computer.
- Run the script, like this:
bash <(curl -s https://gist.github.com/nicholasadamou/ffaf49f0e763f979ebeb86df2a8b215e/raw/d1ca21eeb6b06ae57e3aaeeb76dbbc40123c4378/update.sh)
#!/bin/bash | |
ask_for_sudo() { | |
# Ask for the administrator password upfront. | |
sudo -v &> /dev/null | |
# Update existing `sudo` time stamp | |
# until this script has finished. | |
# | |
# https://gist.github.com/cowboy/3118588 | |
while true; do | |
sudo -n true | |
sleep 60 | |
kill -0 "$$" || exit | |
done &> /dev/null & | |
} | |
show_spinner() { | |
local -r FRAMES='/-\|' | |
# shellcheck disable=SC2034 | |
local -r NUMBER_OR_FRAMES=${#FRAMES} | |
local -r CMDS="$2" | |
local -r MSG="$3" | |
local -r PID="$1" | |
local i=0 | |
local frameText="" | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Note: In order for the Travis CI site to display | |
# things correctly, it needs special treatment, hence, | |
# the "is Travis CI?" checks. | |
if [ "$TRAVIS" != "true" ]; then | |
# Provide more space so that the text hopefully | |
# doesn't reach the bottom line of the terminal window. | |
# | |
# This is a workaround for escape sequences not tracking | |
# the buffer position (accounting for scrolling). | |
# | |
# See also: https://unix.stackexchange.com/a/278888 | |
printf "\n\n\n" | |
tput cuu 3 | |
tput sc | |
fi | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Display spinner while the commands are being executed. | |
while kill -0 "$PID" &>/dev/null; do | |
frameText=" [${FRAMES:i++%NUMBER_OR_FRAMES:1}] $MSG" | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Print frame text. | |
if [ "$TRAVIS" != "true" ]; then | |
printf "%s\n" "$frameText" | |
else | |
printf "%s" "$frameText" | |
fi | |
sleep 0.2 | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Clear frame text. | |
if [ "$TRAVIS" != "true" ]; then | |
tput rc | |
else | |
printf "\r" | |
fi | |
done | |
} | |
execute() { | |
local -r CMDS="$1" | |
local -r MSG="$2" | |
local -r TMP_FILE="$(mktemp /tmp/XXXXX)" | |
local exitCode=0 | |
local cmdsPID="" | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# If the current process is ended, | |
# also end all its subprocesses. | |
set_trap "EXIT" "kill_all_subprocesses" | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Execute commands in background | |
eval "$CMDS" \ | |
&> /dev/null \ | |
2> "$TMP_FILE" & | |
cmdsPID=$! | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Show a spinner if the commands | |
# require more time to complete. | |
show_spinner "$cmdsPID" "$CMDS" "$MSG" | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Wait for the commands to no longer be executing | |
# in the background, and then get their exit code. | |
wait "$cmdsPID" &> /dev/null | |
exitCode=$? | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Print output based on what happened. | |
print_result $exitCode "$MSG" | |
if [ $exitCode -ne 0 ]; then | |
print_error_stream < "$TMP_FILE" | |
fi | |
rm -rf "$TMP_FILE" | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
return $exitCode | |
} | |
set_trap() { | |
trap -p "$1" | grep "$2" &> /dev/null \ | |
|| trap '$2' "$1" | |
} | |
print_error_stream() { | |
while read -r line; do | |
print_error "↳ ERROR: $line" | |
done | |
} | |
print_error() { | |
print_in_red " [✖] $1 $2\n" | |
} | |
print_success() { | |
print_in_green " [✔] $1\n" | |
} | |
print_in_green() { | |
print_in_color "$1" 2 | |
} | |
print_in_purple() { | |
print_in_color "$1" 5 | |
} | |
print_in_red() { | |
print_in_color "$1" 1 | |
} | |
print_in_color() { | |
printf "%b" \ | |
"$(tput setaf "$2" 2> /dev/null)" \ | |
"$1" \ | |
"$(tput sgr0 2> /dev/null)" | |
} | |
print_result() { | |
if [ "$1" -eq 0 ]; then | |
print_success "$2" | |
else | |
print_error "$2" | |
fi | |
return "$1" | |
} | |
update() { | |
# Get macOS Software Updates, and update installed Ruby gems, Homebrew, npm, and their installed packages | |
execute \ | |
"sudo softwareupdate -i -a && \ | |
brew update && brew upgrade && brew cleanup && \ | |
sudo npm install npm -g && sudo npm update -g && \ | |
sudo gem update --system && sudo gem update && sudo gem cleanup" \ | |
"System (update)" | |
} | |
main() { | |
print_in_purple "\n Updating System\n\n" | |
update | |
printf "\n" | |
} | |
main |