Last active
July 22, 2025 02:57
-
-
Save Justinzobel/e062eceecaa31dde689c5d8ec383af6c to your computer and use it in GitHub Desktop.
Alpine - list upgradeable packages in a nice coloured table
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
echo 'Updating repository data ...' | |
apk update | |
# List upgradeable packages into a temporary file | |
apk list --upgradeable | sed -e 's/{//g' -e 's/}//g' -e 's/]//g' > /tmp/apk-upgradeable | |
# Add column headers | |
echo 'Package,Installed Version,New Version' > /tmp/apk-upgradeable-final | |
# Iterate over the file and remove the license stuff in the middle | |
while read line | |
do | |
# existing package | |
section1=$(echo ${line} | cut -d ' ' -f 1) | |
section2=$(echo ${line} | cut -d \) -f 2) | |
newver=$(echo ${section1} | rev | cut -d '-' -f 1-2 | rev) | |
name=$(echo ${section1} | rev | cut -d '-' -f 3- | rev) | |
oldver=$(echo ${section2} | rev | cut -d '-' -f 1-2 | rev) | |
echo "${name},${oldver},${newver}" >> /tmp/apk-upgradeable-final | |
done < /tmp/apk-upgradeable | |
# Set the file variable as the file passed. | |
file=/tmp/apk-upgradeable-final | |
# Colours (just comment out or set to blank for no colour) | |
lineColour1='\e[1;30m' | |
lineColour2='' | |
headerColour='\e[1;33m' | |
borderColour='\e[3;34m' | |
# Clean up temp file if it exists before starting | |
# TODO use a bash array to store this data | |
if [[ -f /tmp/table-column-sizes ]];then rm /tmp/table-column-sizes;fi | |
# Get total lines in the csv file | |
total=$(wc -l ${file} | cut -d ' ' -f 1) | |
# Find longest line for each column | |
i=1 | |
while true | |
do | |
if [[ ${i} -eq ${total} ]];then break;fi | |
echo $(cat ${file} | cut -d , -f ${i} | wc -L | cut -d ' ' -f 1) >> /tmp/table-column-sizes | |
i=$(( i + 1 )) | |
done | |
# Get total number of columns | |
commas=$(head -n 1 ${file} | sed 's/[^,]//g' | awk '{ print length }') | |
columns=$(( ${commas} + 1 )) | |
# Print the header | |
function print_header { | |
printf "${borderColour}┌" | |
for x in $(seq 1 ${columns}) | |
do | |
maxTmp=$(sed "${x}q;d" /tmp/table-column-sizes) | |
max=$(expr ${maxTmp} + 2) | |
for o in $(seq 1 ${max}) | |
do printf '─' | |
done | |
if [[ ${x} -eq ${columns} ]];then printf '┐\n';else printf '┬';fi | |
done | |
printf '│\e[0m' | |
for header in $(seq 1 ${columns}) | |
do | |
headertext=$(head -n 1 ${file} | cut -d , -f ${header}) | |
printf " ${headerColour}%s\e[0m" "${headertext}" | |
# Print padding | |
textlen=$(echo ${headertext} | wc -c) | |
maxTmp=$(sed "${header}q;d" /tmp/table-column-sizes) | |
max=$(expr ${maxTmp} + 3) | |
diff=$(expr ${max} - ${textlen} - 1) | |
for k in $(seq 1 ${diff}) | |
do | |
printf ' ' | |
done | |
printf "${borderColour}│\e[0m" | |
done | |
printf '\n' | |
printf "${borderColour}├" | |
for a in $(seq 1 ${columns}) | |
do | |
maxTmp=$(sed "${a}q;d" /tmp/table-column-sizes) | |
max=$(expr ${maxTmp} + 2) | |
for b in $(seq 1 ${max}) | |
do printf '─' | |
done | |
if [[ ${a} -eq ${columns} ]];then printf '┤\e[0m\n';else printf '┼';fi | |
done | |
} | |
# Print each row | |
function print_data { | |
line=${1} | |
printf "${borderColour}│\e[0m" | |
for data in $(seq 1 ${columns}) | |
do | |
datatext=$(sed "${line}q;d" ${file} | cut -d , -f ${data}) | |
if [[ ${fancy} == 'true' ]] | |
then | |
printf " ${lineColour1}%s\e[0m" "${datatext}" | |
else | |
printf " ${lineColour2}%s\e[0m" "${datatext}" | |
fi | |
# Print padding | |
textlen=$(echo ${datatext} | wc -c) | |
maxTmp=$(sed "${data}q;d" /tmp/table-column-sizes) | |
max=$(expr ${maxTmp} + 3) | |
diff=$(expr ${max} - ${textlen} - 1) | |
for k in $(seq 1 ${diff}) | |
do | |
printf ' ' | |
done | |
printf "${borderColour}│\e[0m" | |
done | |
printf '\n' | |
} | |
# Iterate over each row in the CSV file | |
i=1 | |
while true | |
do | |
if [[ $((${i} % 2)) -eq 0 ]];then fancy=false;else fancy=true;fi | |
if [[ ${i} -eq 1 ]];then print_header;else print_data ${i};fi | |
if [[ ${i} -eq ${total} ]];then break;fi | |
i=$(( i + 1 )) | |
done | |
# Print the bottom of the table | |
printf "${borderColour}└" | |
for g in $(seq 1 ${columns}) | |
do | |
maxTmp=$(sed "${g}q;d" /tmp/table-column-sizes) | |
max=$(expr ${maxTmp} + 2) | |
for h in $(seq 1 ${max}) | |
do printf '─' | |
done | |
if [[ ${g} -eq ${columns} ]];then printf '┘\n\e[0m';else printf '┴';fi | |
done | |
# Clean up temp file | |
if [[ -f /tmp/table-column-sizes ]];then rm /tmp/table-column-sizes;fi | |
# Print hostname so user knows if they're on a remote device | |
echo "Hostname: $(hostname)" | |
# Ask if user wants to proceed with the upgrade | |
read -p 'Upgrade (yes/no): ' ans | |
if [[ ${ans} == 'yes' ]] | |
then | |
echo "Beginning upgrade ..." | |
apk upgrade -a | |
else | |
echo "Aborting" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment