Skip to content

Instantly share code, notes, and snippets.

@nicholasadamou
Last active September 6, 2017 01:06
Show Gist options
  • Save nicholasadamou/5fbde132620829a9c68c94cb04c013c8 to your computer and use it in GitHub Desktop.
Save nicholasadamou/5fbde132620829a9c68c94cb04c013c8 to your computer and use it in GitHub Desktop.
Updates a debian-linux-based computer that uses APT.

Linux Updater Script

Here's a short shell script to quickly update a debian-linux-based computer that uses APT.

  • Run the script, like this: bash <(curl -s https://gist.githubusercontent.com/nicholasadamou/5fbde132620829a9c68c94cb04c013c8/raw/b1ab3ffe6f1b1dd425ff89920d88a5d169e2506e/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"
}
fix_dpkg() {
declare -a files=("/var/lib/dpkg/lock" "/var/cache/apt/archives/lock")
for i in "${files[@]}"
do
# If there is a dpkg lock, then remove it.
if [ -e "$i" ]; then
sudo rm -rf "$i" &> /dev/null
fi
done
}
install_package() {
declare -r PACKAGE="$2"
declare -r PACKAGE_READABLE_NAME="$1"
if ! package_is_installed "$PACKAGE"; then
fix_dpkg
execute "sudo apt-get install --allow-unauthenticated -qqy $PACKAGE" "$PACKAGE_READABLE_NAME"
# suppress output ─┘│
# assume "yes" as the answer to all prompts ──┘
else
print_success "$PACKAGE_READABLE_NAME"
fi
}
package_is_installed() {
dpkg -s "$1" &> /dev/null
}
update() {
ask_for_sudo
fix_dpkg
# Resynchronize the package index files from their sources.
execute \
"sudo apt-get update -qqy" \
"APT (update)"
}
upgrade() {
ask_for_sudo
fix_dpkg
# Install the newest versions of all packages installed.
execute \
"export DEBIAN_FRONTEND=\"noninteractive\" \
&& sudo apt-get -o Dpkg::Options::=\"--force-confnew\" upgrade -qqy" \
"APT (upgrade)"
}
main() {
print_in_purple "\n Updating System\n\n"
update
upgrade
printf "\n"
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment