Skip to content

Instantly share code, notes, and snippets.

@pythoninthegrass
Last active November 13, 2024 19:16
Show Gist options
  • Save pythoninthegrass/b2802cd8220d3053ede12bb85942e9e7 to your computer and use it in GitHub Desktop.
Save pythoninthegrass/b2802cd8220d3053ede12bb85942e9e7 to your computer and use it in GitHub Desktop.
Cleanup ubuntu servers (non)interactively (cf. no disk space left)
#!/usr/bin/env bash
set -euo pipefail
# $USER
[[ -n $(logname >/dev/null 2>&1) ]] && logged_in_user=$(logname) || logged_in_user=$(whoami)
# $UID
# logged_in_uid=$(id -u "${logged_in_user}")
# $HOME
logged_in_home=$(eval echo "~${logged_in_user}")
get_current_kernel() {
uname -r
}
get_installed_kernels() {
dpkg-query -f '${Package}\n' -W 'linux-image-*' | grep -v meta
}
cleanup_kernels() {
local current_kernel=$(get_current_kernel)
echo "Current kernel: $current_kernel"
echo "Keeping current kernel and two previous versions..."
# Keep the last three kernels including the current one
kernels_to_keep=$(dpkg-query -f '${Package}\n' -W 'linux-image-*' |
grep -v meta |
grep -v "linux-image-${current_kernel}" |
sort -V |
tail -n 2)
# Add current kernel to keep list
kernels_to_keep="linux-image-${current_kernel} ${kernels_to_keep}"
echo "Keeping kernels: ${kernels_to_keep}"
# Remove other kernels, explicitly excluding the ones we want to keep
dpkg-query -f '${Package}\n' -W 'linux-image-*' \
| grep -v meta \
| grep -v -E "$(echo $kernels_to_keep | tr ' ' '|')" \
| xargs -r apt-get -y purge
# Cleanup any remaining configs
dpkg -l | grep '^rc' | awk '{print $2}' | grep linux-image | xargs -r dpkg --purge
}
# Package management cleanup
cleanup_packages() {
echo "Cleaning package cache..."
apt-get clean
apt-get autoremove --purge -y
echo "Removing old package lists..."
rm -rf /var/lib/apt/lists/*
apt-get update
}
# Log cleanup
cleanup_logs() {
echo "Cleaning system logs..."
# Cleanup journal
journalctl --vacuum-time=1d
# Clean old logs
find /var/log -type f -name "*.gz" -delete
find /var/log -type f -name "*.log.*" -delete
# Truncate active logs
find /var/log -type f -name "*.log" -exec tee {} \; < /dev/null
find /var/log -type f -name "messages" -exec tee {} \; < /dev/null
find /var/log -type f -name "syslog" -exec tee {} \; < /dev/null
}
# Docker cleanup
cleanup_docker() {
if command -v docker &> /dev/null; then
echo "Cleaning Docker resources..."
docker images -f "dangling=true" -q | xargs -r docker rmi || true
fi
}
# Temporary files cleanup
cleanup_temp() {
echo "Cleaning temporary files..."
rm -rf /tmp/*
rm -rf /var/tmp/*
# Clean user cache dirs over 7 days old
find ${logged_in_user}/*/.cache -type f -atime +7 -delete 2>/dev/null || true
}
# User specific cleanup
cleanup_user() {
echo "Cleaning user files..."
# Clean bash history
truncate -s 0 ${logged_in_home}/.bash_history
# Clean thumbnails
rm -rf ${logged_in_home}/.cache/thumbnails/*
# Clean trash
rm -rf ${logged_in_home}/.local/share/Trash/*
}
# Find large files
find_large_files() {
local min_size=${1:-"100M"}
echo "Finding files larger than $min_size..."
find / -type f -size +$min_size -exec ls -lh {} \; 2>/dev/null
}
# Show disk usage
show_disk_usage() {
echo "Current disk usage by directory:"
du -hax / 2>/dev/null | sort -rh | head -n 20
}
# Full cleanup function
full_cleanup() {
local show_large_files=${1:-false}
echo "Starting full system cleanup..."
# Show initial disk usage
df -h /
cleanup_kernels
cleanup_packages
cleanup_logs
cleanup_docker
cleanup_temp
cleanup_user
echo -e "\nCleanup completed. Current disk usage:"
df -h /
if [[ "$show_large_files" == true ]]; then
find_large_files
show_disk_usage
fi
}
# Print usage
print_usage() {
echo "Usage: $0 [-n] {kernels|packages|logs|docker|temp|user|large-files|usage|all} [size]"
echo
echo "Options:"
echo " -n Non-interactive mode"
echo " -l Show large files after cleanup (only with 'all' command)"
echo
echo "Commands:"
echo " kernels Clean old kernel packages"
echo " packages Clean package cache and remove unused packages"
echo " logs Clean system logs"
echo " docker Clean Docker resources"
echo " temp Clean temporary files"
echo " user Clean user-specific files"
echo " large-files Find large files (optional size parameter, default 100M)"
echo " usage Show disk usage"
echo " all Perform full system cleanup"
}
# Main function
main() {
# Check if running as root
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
local NONINTERACTIVE=false
local SHOW_LARGE_FILES=false
# Parse options
while getopts ":nl" opt; do
case ${opt} in
n)
NONINTERACTIVE=true
;;
l)
SHOW_LARGE_FILES=true
;;
\?)
echo "Invalid option: -$OPTARG"
print_usage
exit 1
;;
esac
done
shift $((OPTIND -1))
# Check if command is provided
if [[ $# -lt 1 ]]; then
print_usage
exit 0
fi
local command=$1
shift
if [[ "$NONINTERACTIVE" = false && "$command" = "all" ]]; then
echo -e "\nWould you like to perform a full system cleanup? (y/n)"
read -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
echo "Operation cancelled."
exit 0
fi
fi
case "$command" in
kernels)
cleanup_kernels
;;
packages)
cleanup_packages
;;
logs)
cleanup_logs
;;
docker)
cleanup_docker
;;
temp)
cleanup_temp
;;
user)
cleanup_user
;;
large-files)
find_large_files "${1:-100M}"
;;
usage)
show_disk_usage
;;
all)
full_cleanup "$SHOW_LARGE_FILES"
;;
*)
echo "Invalid command: $command"
print_usage
exit 1
;;
esac
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment