Skip to content

Instantly share code, notes, and snippets.

@Limbicnation
Last active October 15, 2025 07:34
Show Gist options
  • Select an option

  • Save Limbicnation/6763b69ab6a406790f3b7d4b56a2f6e8 to your computer and use it in GitHub Desktop.

Select an option

Save Limbicnation/6763b69ab6a406790f3b7d4b56a2f6e8 to your computer and use it in GitHub Desktop.
ubuntu_cleanup.sh A comprehensive system cleanup script for Ubuntu 24.04 that safely removes unnecessary files to free up disk space. This script includes system maintenance tasks like package cleanup, log rotation, cache removal, and system optimization. Features include progress tracking, disk space reporting, resource limiting, and extensive …
#!/usr/bin/env bash
# Security-Hardened Ubuntu Cleanup Script
# This script performs comprehensive system cleanup with enterprise-grade security
# EXCLUDES: hy3dgen folder from any deletion operations
#
# Security improvements:
# - Comprehensive error handling with trap handlers
# - Safe configuration loading without arbitrary code execution
# - APT and script-level locking mechanisms
# - Kernel retention validation (N-1 policy)
# - System snapshot before destructive operations
# - Syslog integration for audit trail
# - Resource limit enforcement
# - Proper exit codes for monitoring
# Exit codes
readonly EXIT_SUCCESS=0
readonly EXIT_LOCK_FAILED=1
readonly EXIT_APT_LOCKED=2
readonly EXIT_NO_PRIVILEGES=3
readonly EXIT_DEPENDENCY_MISSING=4
readonly EXIT_USER_ABORT=5
readonly EXIT_OPERATION_FAILED=10
readonly EXIT_CONFIG_INVALID=11
# Strict error handling
set -euo pipefail
IFS=$'\n\t'
# Configuration variables
CONFIG_FILE="${HOME}/.config/ubuntu_cleanup.conf"
LOG_DIR="/var/log/system_cleanup"
LOG_FILE="${LOG_DIR}/cleanup_$(date +%Y%m%d_%H%M%S).log"
LOCK_FILE="/var/lock/ubuntu_cleanup.lock"
LOCK_FD=200
DRY_RUN=0
VERBOSE=0
TIMEOUT_DURATION=60
PARALLEL_JOBS=2
MAX_RESOURCE_USAGE=50
DEFAULT_RETENTION_DAYS=10
HAS_ROOT=0
# EXCLUSION PATTERNS - Add folders/files to protect here
EXCLUDED_PATTERNS=(
"hy3dgen"
"Hunyuan3D"
"huggingface"
".git"
".venv"
"node_modules"
"venv"
"env"
".env"
)
# Logging function with syslog integration
log_operation() {
local severity=$1
local message=$2
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$severity] $message"
# Send to syslog if logger is available
if command -v logger &>/dev/null; then
logger -t ubuntu_cleanup -p "user.$severity" "$message"
fi
}
# Cleanup handler for trap
cleanup_on_error() {
local exit_code=$?
if [ $exit_code -ne 0 ]; then
log_operation "err" "Script failed with exit code $exit_code at line ${BASH_LINENO[0]}"
log_operation "err" "Failed command: ${BASH_COMMAND}"
fi
# Release lock if held
release_lock
exit $exit_code
}
# Set trap handlers
trap cleanup_on_error ERR EXIT
trap 'log_operation "warning" "Script interrupted by user"; exit $EXIT_USER_ABORT' SIGTERM SIGINT
# Create log directory if it doesn't exist with proper permissions
mkdir -p "$LOG_DIR" 2>/dev/null || true
chmod 750 "$LOG_DIR" 2>/dev/null || true
# Setup logging with rotation
exec > >(tee -a "$LOG_FILE") 2>&1
# Safe configuration loader - no arbitrary code execution
load_safe_config() {
if [ ! -f "$CONFIG_FILE" ]; then
return 0
fi
log_operation "info" "Loading configuration from $CONFIG_FILE"
# Validate config file syntax
if ! grep -qE '^\s*(#|[A-Z_]+=|$)' "$CONFIG_FILE"; then
log_operation "err" "Config file contains invalid syntax"
return $EXIT_CONFIG_INVALID
fi
# Load only whitelisted variables with validation
while IFS='=' read -r key value; do
# Skip comments and empty lines
[[ "$key" =~ ^#.*$ || -z "$key" ]] && continue
# Remove leading/trailing whitespace
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs)
case "$key" in
TIMEOUT_DURATION|PARALLEL_JOBS|MAX_RESOURCE_USAGE|DEFAULT_RETENTION_DAYS)
# Validate value is numeric and within reasonable range
if [[ "$value" =~ ^[0-9]+$ ]] && [ "$value" -ge 1 ] && [ "$value" -le 9999 ]; then
declare -g "$key=$value"
log_operation "info" "Loaded config: $key=$value"
else
log_operation "warning" "Invalid value for $key: $value (skipped)"
fi
;;
*)
log_operation "warning" "Unknown config variable: $key (skipped)"
;;
esac
done < <(grep -v '^#' "$CONFIG_FILE" | grep -v '^$')
}
# Script-level locking mechanism
acquire_lock() {
exec 200>"$LOCK_FILE"
if ! flock -n 200; then
log_operation "err" "Another instance is already running"
exit $EXIT_LOCK_FAILED
fi
echo $$ >&200
log_operation "info" "Lock acquired (PID: $$)"
}
release_lock() {
if [ -n "${LOCK_FD:-}" ]; then
flock -u $LOCK_FD 2>/dev/null || true
rm -f "$LOCK_FILE" 2>/dev/null || true
fi
}
# APT lock checking with timeout
check_apt_lock() {
local max_wait=300 # 5 minutes
local waited=0
local lock_files=(
"/var/lib/dpkg/lock-frontend"
"/var/lib/apt/lists/lock"
"/var/cache/apt/archives/lock"
)
while true; do
local locked=0
for lock_file in "${lock_files[@]}"; do
if fuser "$lock_file" >/dev/null 2>&1; then
locked=1
break
fi
done
if [ $locked -eq 0 ]; then
return 0
fi
if [ $waited -ge $max_wait ]; then
log_operation "err" "APT lock held for $max_wait seconds, aborting"
exit $EXIT_APT_LOCKED
fi
log_operation "warning" "Waiting for APT lock to be released... ($waited/$max_wait seconds)"
sleep 5
waited=$((waited + 5))
done
}
# Check for root privileges
check_root() {
if [[ $EUID -eq 0 ]]; then
HAS_ROOT=1
log_operation "info" "Running with root privileges"
else
HAS_ROOT=0
log_operation "info" "Running without root, will use sudo for privileged operations"
# Test sudo access
if ! sudo -n true 2>/dev/null; then
log_operation "warning" "Sudo password may be required"
fi
fi
}
# Function to handle privileged commands (no eval!)
run_with_privileges() {
if [[ $HAS_ROOT -eq 1 ]]; then
"$@"
else
sudo "$@"
fi
}
# Resource limit enforcement
enforce_resource_limits() {
# Set nice priority for CPU
renice -n 10 -p $$ >/dev/null 2>&1 || true
# Set ionice for disk I/O (idle class)
if command -v ionice &>/dev/null; then
ionice -c 3 -p $$ >/dev/null 2>&1 || true
fi
log_operation "info" "Resource limits enforced: nice=10, ionice=idle"
}
# Enhanced path validation with parent directory checking
is_safe_path() {
local path=$1
# Resolve to absolute path
local abs_path
abs_path=$(readlink -f "$path" 2>/dev/null) || {
log_operation "warning" "Cannot resolve path: $path"
return 1
}
# Critical system paths and their subdirectories
local dangerous_paths=(
"/"
"/bin"
"/boot"
"/dev"
"/etc"
"/lib"
"/lib64"
"/proc"
"/root"
"/sbin"
"/sys"
"/usr"
)
for dangerous_path in "${dangerous_paths[@]}"; do
# Check if path is exactly the dangerous path or under it
if [[ "$abs_path" == "$dangerous_path" ]] || [[ "$abs_path" == "$dangerous_path"/* ]]; then
log_operation "err" "Refusing to remove path under critical system directory: $abs_path"
return 1
fi
done
return 0
}
# Function to check if path should be excluded
is_excluded() {
local path=$1
for pattern in "${EXCLUDED_PATTERNS[@]}"; do
if [[ "$path" == *"$pattern"* ]]; then
log_operation "info" "Excluding protected path: $path (matches pattern: $pattern)"
return 0
fi
done
return 1
}
# Function for timeout handling with user prompts
prompt_with_timeout() {
local prompt=$1
local timeout=$TIMEOUT_DURATION
local response
read -t "$timeout" -p "$prompt" response || true
if [ -z "$response" ]; then
echo "Timeout reached, assuming default answer (n)"
return 1
fi
if [[ "$response" =~ ^[Yy]$ ]]; then
return 0
else
return 1
fi
}
# Function to safely remove files with exclusion check
safe_remove() {
local target=$1
local force=${2:-0}
# Check if target should be excluded
if is_excluded "$target"; then
return 0
fi
# Check if path is safe
if ! is_safe_path "$target"; then
return 1
fi
# Check if target exists
if [ ! -e "$target" ]; then
[ $VERBOSE -eq 1 ] && log_operation "info" "Target does not exist, skipping: $target"
return 0
fi
# Safe removal
if [ -d "$target" ] && [ ! -L "$target" ]; then
log_operation "info" "Removing contents of directory $target"
if [ $force -eq 1 ]; then
rm -rf "${target:?}"/* 2>/dev/null || true
else
rm -r "${target:?}"/* 2>/dev/null || true
fi
else
log_operation "info" "Removing $target"
if [ $force -eq 1 ]; then
rm -f "$target" 2>/dev/null || true
else
rm "$target" 2>/dev/null || true
fi
fi
return 0
}
# Enhanced find command that excludes protected patterns
safe_find() {
local base_path=$1
shift
local find_args=("$@")
# Build exclusion arguments for find
local exclude_args=()
for pattern in "${EXCLUDED_PATTERNS[@]}"; do
exclude_args+=(-not -path "*${pattern}*")
done
find "$base_path" "${exclude_args[@]}" "${find_args[@]}" 2>/dev/null || true
}
# System snapshot before destructive operations
create_system_snapshot() {
local snapshot_dir="/var/backups/ubuntu_cleanup_$(date +%Y%m%d_%H%M%S)"
log_operation "info" "Creating system snapshot: $snapshot_dir"
run_with_privileges mkdir -p "$snapshot_dir"
# Backup package state
dpkg --get-selections > "$snapshot_dir/package_selections.txt" 2>/dev/null || true
apt-mark showmanual > "$snapshot_dir/manual_packages.txt" 2>/dev/null || true
# Backup kernel list
dpkg -l | grep -E 'linux-image|linux-headers' > "$snapshot_dir/kernel_list.txt" 2>/dev/null || true
# Backup sources list
run_with_privileges cp -r /etc/apt/sources.list* "$snapshot_dir/" 2>/dev/null || true
log_operation "info" "System snapshot created: $snapshot_dir"
echo "$snapshot_dir" > /tmp/ubuntu_cleanup_snapshot.path
}
# Safe kernel cleanup with N-1 retention validation
safe_kernel_cleanup() {
local current_kernel=$(uname -r)
local installed_kernels
installed_kernels=$(dpkg -l | grep -E '^ii.*linux-image-[0-9]' | awk '{print $2}' | grep -v "linux-image-generic" || true)
local kernel_count=$(echo "$installed_kernels" | grep -v '^$' | wc -l)
log_operation "info" "Current kernel: $current_kernel"
log_operation "info" "Installed kernels count: $kernel_count"
if [ $kernel_count -le 2 ]; then
log_operation "warning" "Only $kernel_count kernels installed. Skipping cleanup to maintain N-1 policy (minimum 2 kernels required)"
return 0
fi
echo "Installed kernels:"
echo "$installed_kernels"
echo ""
echo "This will retain current kernel + at least 1 previous version"
if prompt_with_timeout "Remove old kernels (keeping current + 1)? (y/n): "; then
check_apt_lock
if run_with_privileges apt-get autoremove --purge -y; then
log_operation "info" "Kernel cleanup completed successfully"
# Verify we still have enough kernels
local remaining_kernels
remaining_kernels=$(dpkg -l | grep -E '^ii.*linux-image-[0-9]' | awk '{print $2}' | grep -v "linux-image-generic" | wc -l)
if [ $remaining_kernels -lt 2 ]; then
log_operation "err" "CRITICAL: Less than 2 kernels remaining after cleanup!"
return 1
fi
log_operation "info" "Remaining kernels: $remaining_kernels"
else
log_operation "err" "Kernel cleanup failed"
return 1
fi
fi
}
# Log rotation for script logs
rotate_old_logs() {
log_operation "info" "Rotating old cleanup logs"
# Keep only last 30 days of cleanup logs
find "$LOG_DIR" -name "cleanup_*.log" -mtime +30 -delete 2>/dev/null || true
# Keep max 50 log files
local log_files
log_files=$(ls -t "$LOG_DIR"/cleanup_*.log 2>/dev/null | tail -n +51)
if [ -n "$log_files" ]; then
echo "$log_files" | xargs rm -f 2>/dev/null || true
fi
}
# Check dependencies
check_dependencies() {
local missing_tools=()
for tool in apt-get find grep awk bc fuser flock; do
if ! command -v "$tool" &>/dev/null; then
missing_tools+=("$tool")
fi
done
if [ ${#missing_tools[@]} -gt 0 ]; then
log_operation "err" "Missing required tools: ${missing_tools[*]}"
exit $EXIT_DEPENDENCY_MISSING
fi
}
# Record initial disk space
record_disk_space() {
log_operation "info" "Initial disk space usage:"
df -h / /home
initial_space=$(df / | awk 'NR==2 {print $4}')
}
# Parse command line options
while getopts "dnvt:j:r:k:" opt; do
case $opt in
d|n) DRY_RUN=1 ;;
v) VERBOSE=1 ;;
t) TIMEOUT_DURATION=$OPTARG ;;
j) PARALLEL_JOBS=$OPTARG ;;
r) MAX_RESOURCE_USAGE=$OPTARG ;;
k) DEFAULT_RETENTION_DAYS=$OPTARG ;;
*) echo "Usage: $0 [-d|-n] [-v] [-t timeout] [-j jobs] [-r max_cpu] [-k retention_days]" >&2
echo " -d,-n Dry run (show what would be done)"
echo " -v Verbose output"
echo " -t Timeout for user prompts in seconds (default: 60)"
echo " -j Number of parallel jobs (default: 2)"
echo " -r Maximum CPU percentage (default: 50)"
echo " -k Retention days for logs (default: 10)"
exit 1 ;;
esac
done
# Progress function
total_steps=20
current_step=0
progress() {
current_step=$((current_step + 1))
percentage=$((current_step * 100 / total_steps))
log_operation "info" "[$current_step/$total_steps - $percentage%] $1"
}
# Main execution starts here
log_operation "info" "=== Ubuntu Cleanup Script (Hardened) Started ==="
log_operation "info" "PID: $$"
# Acquire lock first
acquire_lock
# Load configuration safely
load_safe_config || exit $EXIT_CONFIG_INVALID
# Initialize
check_dependencies
check_root
enforce_resource_limits
rotate_old_logs
record_disk_space
log_operation "info" "Protected patterns: ${EXCLUDED_PATTERNS[*]}"
[ $DRY_RUN -eq 1 ] && log_operation "warning" "DRY RUN MODE - No changes will be made"
# Confirmation prompt
if [ $DRY_RUN -eq 0 ]; then
if ! prompt_with_timeout "Proceed with cleanup? (y/n): "; then
log_operation "warning" "User aborted cleanup"
exit $EXIT_USER_ABORT
fi
# Create system snapshot before any destructive operations
create_system_snapshot
fi
# 1. Update package list
progress "Updating package list"
if [ $DRY_RUN -eq 0 ]; then
check_apt_lock
run_with_privileges apt-get update || log_operation "warning" "Failed to update package list"
fi
# 2. Clear user cache (with exclusions)
progress "Clearing user cache (excluding protected folders)"
if [ $DRY_RUN -eq 0 ]; then
cache_size_before=$(du -sh ~/.cache 2>/dev/null | cut -f1)
log_operation "info" "Cache size before: $cache_size_before"
# Remove cache files older than 3 days, excluding protected patterns
safe_find ~/.cache -type f -mtime +3 -delete
cache_size_after=$(du -sh ~/.cache 2>/dev/null | cut -f1)
log_operation "info" "Cache size after: $cache_size_after"
fi
# 3. Clean APT cache
progress "Cleaning APT cache"
if [ $DRY_RUN -eq 0 ]; then
check_apt_lock
run_with_privileges apt-get clean
fi
# 4. Remove obsolete packages
progress "Removing obsolete packages"
if [ $DRY_RUN -eq 0 ]; then
check_apt_lock
run_with_privileges apt-get autoclean
fi
# 5. Remove unused packages
progress "Removing unused packages"
if [ $DRY_RUN -eq 0 ]; then
check_apt_lock
log_operation "info" "Packages to be removed:"
run_with_privileges apt-get autoremove -y --dry-run | grep "^Remv" || log_operation "info" "No packages to remove"
if prompt_with_timeout "Remove these packages? (y/n): "; then
run_with_privileges apt-get autoremove -y
fi
fi
# 6. Remove old kernels (SAFE with N-1 validation)
progress "Checking old kernel versions"
if [ $DRY_RUN -eq 0 ]; then
safe_kernel_cleanup
fi
# 7. Clean Snap packages
progress "Cleaning Snap packages"
if [ $DRY_RUN -eq 0 ] && command -v snap &> /dev/null; then
run_with_privileges snap list --all | awk '/disabled/{print $1, $3}' | \
while read -r snapname revision; do
log_operation "info" "Removing $snapname revision $revision"
run_with_privileges snap remove "$snapname" --revision="$revision" || true
done
fi
# 8. Clean Flatpak
progress "Cleaning Flatpak"
if [ $DRY_RUN -eq 0 ] && command -v flatpak &> /dev/null; then
run_with_privileges flatpak uninstall --unused -y || true
fi
# 9. Clear thumbnails (with age limit)
progress "Clearing old thumbnails"
if [ $DRY_RUN -eq 0 ]; then
safe_find ~/.cache/thumbnails -type f -mtime +30 -delete
fi
# 10. Clean journal logs
progress "Cleaning systemd journal logs"
if [ $DRY_RUN -eq 0 ] && command -v journalctl &> /dev/null; then
run_with_privileges journalctl --vacuum-time="${DEFAULT_RETENTION_DAYS}d"
run_with_privileges journalctl --vacuum-size=50M
fi
# 11. Clean /tmp (carefully)
progress "Cleaning /tmp directory"
if [ $DRY_RUN -eq 0 ]; then
# Only remove files older than retention days and not in use
run_with_privileges find /tmp -type f -atime +$DEFAULT_RETENTION_DAYS \
-not -exec fuser -s {} \; -delete 2>/dev/null || true
fi
# 12. Clean browser caches (with exclusions)
progress "Cleaning browser caches"
if [ $DRY_RUN -eq 0 ]; then
# Firefox
if [ -d ~/.mozilla/firefox ]; then
safe_find ~/.mozilla/firefox -name "*Cache*" -type d -exec rm -rf {} + 2>/dev/null || true
fi
# Chrome/Chromium
for browser_dir in ~/.config/google-chrome ~/.config/chromium; do
if [ -d "$browser_dir" ]; then
safe_find "$browser_dir" -name "Cache" -type d -exec rm -rf {} + 2>/dev/null || true
fi
done
fi
# 13. Manage log files
progress "Managing log files"
if [ $DRY_RUN -eq 0 ]; then
# Compress old logs
run_with_privileges find /var/log -type f -name "*.log" -mtime +7 ! -exec fuser -s {} \; -exec gzip -9 {} \; 2>/dev/null || true
# Remove very old compressed logs
run_with_privileges find /var/log -type f -name "*.gz" -mtime +$DEFAULT_RETENTION_DAYS -delete 2>/dev/null || true
fi
# 14. Check core dumps
progress "Checking core dumps"
if [ $DRY_RUN -eq 0 ] && [ -d /var/lib/apport/coredump ]; then
core_count=$(find /var/lib/apport/coredump -type f -name "core*" 2>/dev/null | wc -l)
if [ $core_count -gt 0 ]; then
log_operation "info" "Found $core_count core dump files"
if prompt_with_timeout "Delete core dumps? (y/n): "; then
run_with_privileges find /var/lib/apport/coredump -type f -name 'core*' -delete
fi
fi
fi
# 15. Clean package backups
progress "Cleaning package backups"
if [ $DRY_RUN -eq 0 ]; then
# Keep only recent backups (last 5)
run_with_privileges bash -c "ls -t /var/backups/dpkg.status.* 2>/dev/null | tail -n +6 | xargs rm -f" 2>/dev/null || true
fi
# 16. Clean pip cache
progress "Cleaning pip cache"
if [ $DRY_RUN -eq 0 ] && command -v pip &> /dev/null; then
pip cache purge 2>/dev/null || true
fi
# 17. Clean conda cache
progress "Cleaning conda cache"
if [ $DRY_RUN -eq 0 ] && command -v conda &> /dev/null; then
conda clean --all -y 2>/dev/null || true
fi
# 18. Clean npm cache
progress "Cleaning npm cache"
if [ $DRY_RUN -eq 0 ] && [ -d ~/.npm ]; then
# Exclude node_modules and other important npm folders
safe_find ~/.npm/_cache -type f -mtime +7 -delete 2>/dev/null || true
fi
# 19. REMOVED: Automatic PPA addition (security risk)
progress "Skipping automatic third-party repository addition"
log_operation "info" "Automatic PPA addition removed for security. Install ucaresystem-core manually if needed."
# 20. Final update
progress "Final system update"
if [ $DRY_RUN -eq 0 ]; then
if prompt_with_timeout "Update all packages? (y/n): "; then
check_apt_lock
run_with_privileges apt-get update && run_with_privileges apt-get upgrade -y
fi
fi
# Show results
log_operation "info" "Final disk space usage:"
df -h / /home
final_space=$(df / | awk 'NR==2 {print $4}')
log_operation "info" "=== Cleanup completed successfully ==="
log_operation "info" "Initial free space: $initial_space KB"
log_operation "info" "Final free space: $final_space KB"
space_freed=$((final_space - initial_space))
log_operation "info" "Space freed: $space_freed KB"
log_operation "info" "Log file: $LOG_FILE"
log_operation "info" "Protected patterns excluded: ${EXCLUDED_PATTERNS[*]}"
if [ -f /tmp/ubuntu_cleanup_snapshot.path ]; then
snapshot_path=$(cat /tmp/ubuntu_cleanup_snapshot.path)
log_operation "info" "System snapshot available at: $snapshot_path"
rm -f /tmp/ubuntu_cleanup_snapshot.path
fi
exit $EXIT_SUCCESS
@5taras
Copy link

5taras commented Feb 26, 2025

./ubuntu_cleanup.sh: 27: Syntax error: redirection unexpected

@Limbicnation
Copy link
Author

@5taras I have changed it to: #!/usr/bin/env bash

This will fix your "redirection unexpected" error by making sure the script runs with bash, which supports the process substitution syntax you're using.

Please use the script with caution!

@5taras
Copy link

5taras commented Feb 27, 2025

Useful script. I'd add localepurge too. I found also a useful ucaresystem-core app.

@Limbicnation
Copy link
Author

I updated the script to make it safer, and now you can be more selective about which folders you want to remove from the .cache

✅ Shebang line: Uses #!/usr/bin/env bash (already implemented)
✅ localepurge: Added with automatic installation prompt
✅ ucaresystem-core: Added with automatic installation prompt

What these tools do:

localepurge:

Removes unnecessary locale files (language packs)
Can free up significant space if you only use one or two languages
Automatically configures which locales to keep during installation

ucaresystem-core:

All-in-one Ubuntu maintenance tool
Performs: updates, removes old kernels, cleans apt cache, removes orphaned packages
Basically does many of the same tasks but in one command
The -u flag runs it in unattended mode

@yashraj22
Copy link

yashraj22 commented Aug 23, 2025

image

how can we fix this in localpurge can't navigate on clicking any button it shows thses character instead of navigating/selecting

@Limbicnation
Copy link
Author

This script is specifically designed for Ubuntu/Debian systems and uses Linux-specific commands that don't exist on macOS.

@yashraj22
Copy link

I am using a macos theme, this is Ubuntu 24.04 : )

@Limbicnation
Copy link
Author

Hi, thanks for reporting this issue!

I've identified the problem - the interactive localepurge dialog in Step #19 was causing the script to hang. I've updated the script to resolve this issue for now.

Fix: Step #19 has been replaced with:

# 19. Localepurge - Remove unnecessary locale files (SKIPPED)
progress "Skipping locale files cleanup"
if [ $DRY_RUN -eq 0 ]; then
    echo "Localepurge step skipped to avoid interactive dialog" 
    echo "✓ Locale cleanup skipped"
fi

@yashraj22
Copy link

Thank you so much : )

@Limbicnation
Copy link
Author

You're welcome! Thank you for reporting the issue. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment