Created
April 13, 2026 00:34
-
-
Save radityagumay/8cda5c0785d5750cc1dedf7b55e78704 to your computer and use it in GitHub Desktop.
A scripts to delete android build directories
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/bash | |
| # ╔══════════════════════════════════════════════════════════════════╗ | |
| # ║ clean_android_builds.sh — README ║ | |
| # ╠══════════════════════════════════════════════════════════════════╣ | |
| # ║ ║ | |
| # ║ DESCRIPTION ║ | |
| # ║ Recursively removes all `build/` directories across every ║ | |
| # ║ module in every Android project under a given root directory. ║ | |
| # ║ Gradle build outputs can balloon to several GBs over time; ║ | |
| # ║ this script reclaims that space safely and quickly. ║ | |
| # ║ ║ | |
| # ║ USAGE ║ | |
| # ║ ./clean_android_builds.sh [OPTIONS] [root_dir] ║ | |
| # ║ ║ | |
| # ║ OPTIONS ║ | |
| # ║ --dry-run Preview deletions without removing anything. ║ | |
| # ║ Always run this first to sanity-check the list. ║ | |
| # ║ --help Show usage information and exit. ║ | |
| # ║ ║ | |
| # ║ ARGUMENTS ║ | |
| # ║ root_dir Path to the folder containing your Android ║ | |
| # ║ projects. Flags and path can be in any order. ║ | |
| # ║ Default: /Users/raditya.gumay/Documents/ ║ | |
| # ║ AndroidProjects ║ | |
| # ║ ║ | |
| # ║ EXAMPLES ║ | |
| # ║ # Preview what would be deleted (safe, no changes) ║ | |
| # ║ ./clean_android_builds.sh --dry-run ║ | |
| # ║ ║ | |
| # ║ # Delete all build dirs under the default root ║ | |
| # ║ ./clean_android_builds.sh ║ | |
| # ║ ║ | |
| # ║ # Delete build dirs under a custom path ║ | |
| # ║ ./clean_android_builds.sh ~/Projects/MyAndroidApps ║ | |
| # ║ ║ | |
| # ║ # Dry run against a custom path ║ | |
| # ║ ./clean_android_builds.sh --dry-run ~/Projects/MyAndroidApps ║ | |
| # ║ ║ | |
| # ║ WHAT IT CLEANS ║ | |
| # ║ Every directory named `build/` found recursively under ║ | |
| # ║ root_dir. This covers: ║ | |
| # ║ • Top-level project build/ ║ | |
| # ║ • Per-module build/ (app, core, feature-*, etc.) ║ | |
| # ║ It does NOT delete: ║ | |
| # ║ • build/ dirs nested inside another build/ (deduped) ║ | |
| # ║ • Anything inside .git/ directories ║ | |
| # ║ ║ | |
| # ║ SETUP ║ | |
| # ║ chmod +x clean_android_builds.sh ║ | |
| # ║ ║ | |
| # ║ REQUIREMENTS ║ | |
| # ║ bash, find, du, bc (all available by default on macOS) ║ | |
| # ║ ║ | |
| # ║ AUTHOR ║ | |
| # ║ Raditya Gumay — GoTo Maps & Navigation Platform ║ | |
| # ║ ║ | |
| # ╚══════════════════════════════════════════════════════════════════╝ | |
| ROOT_DIR="/Users/raditya.gumay/Documents/AndroidProjects" | |
| DRY_RUN=false | |
| TOTAL_FREED=0 | |
| CLEANED_COUNT=0 | |
| SKIPPED_COUNT=0 | |
| # ── Parse flags ────────────────────────────────────────────── | |
| for arg in "$@"; do | |
| case $arg in | |
| --dry-run) DRY_RUN=true ;; | |
| --help) | |
| echo "Usage: $0 [--dry-run] [root_dir]" | |
| echo "" | |
| echo " root_dir Root directory containing your Android projects." | |
| echo " Default: /Users/raditya.gumay/Documents/AndroidProjects" | |
| echo " --dry-run Preview what would be deleted without removing anything." | |
| exit 0 | |
| ;; | |
| --*) echo "Unknown flag: $arg"; exit 1 ;; | |
| *) ROOT_DIR="$arg" ;; | |
| esac | |
| done | |
| # ── Colors ─────────────────────────────────────────────────── | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| CYAN='\033[0;36m' | |
| BOLD='\033[1m' | |
| RESET='\033[0m' | |
| # ── Helpers ────────────────────────────────────────────────── | |
| human_readable_size() { | |
| local size=$1 | |
| if [ "$size" -ge 1073741824 ]; then | |
| echo "$(echo "scale=2; $size/1073741824" | bc) GB" | |
| elif [ "$size" -ge 1048576 ]; then | |
| echo "$(echo "scale=2; $size/1048576" | bc) MB" | |
| elif [ "$size" -ge 1024 ]; then | |
| echo "$(echo "scale=2; $size/1024" | bc) KB" | |
| else | |
| echo "${size} B" | |
| fi | |
| } | |
| dir_size_bytes() { | |
| du -sk "$1" 2>/dev/null | awk '{print $1 * 1024}' | |
| } | |
| # ── Validate root dir ──────────────────────────────────────── | |
| if [ ! -d "$ROOT_DIR" ]; then | |
| echo -e "${RED}Error: Directory '$ROOT_DIR' does not exist.${RESET}" | |
| exit 1 | |
| fi | |
| echo "" | |
| echo -e "${BOLD}╔══════════════════════════════════════════════════╗${RESET}" | |
| echo -e "${BOLD}║ Android Build Directory Cleaner ║${RESET}" | |
| echo -e "${BOLD}╚══════════════════════════════════════════════════╝${RESET}" | |
| echo "" | |
| echo -e " 📁 Root : ${CYAN}$ROOT_DIR${RESET}" | |
| if $DRY_RUN; then | |
| echo -e " 🔍 Mode : ${YELLOW}DRY RUN (nothing will be deleted)${RESET}" | |
| else | |
| echo -e " 🗑️ Mode : ${RED}LIVE (build dirs will be deleted)${RESET}" | |
| fi | |
| echo "" | |
| # ── Ask for confirmation unless dry-run ────────────────────── | |
| if ! $DRY_RUN; then | |
| read -r -p " Continue? [y/N] " confirm | |
| case "$confirm" in | |
| [yY][eE][sS]|[yY]) echo "" ;; | |
| *) | |
| echo -e "\n ${YELLOW}Aborted.${RESET}\n" | |
| exit 0 | |
| ;; | |
| esac | |
| fi | |
| # ── Find and process all build/ directories ────────────────── | |
| # Exclude any build/ dir that is itself inside another build/ dir | |
| # to avoid double-counting nested hits. | |
| while IFS= read -r build_dir; do | |
| size_bytes=$(dir_size_bytes "$build_dir") | |
| size_human=$(human_readable_size "$size_bytes") | |
| if $DRY_RUN; then | |
| echo -e " ${YELLOW}[DRY RUN]${RESET} Would remove: ${CYAN}$build_dir${RESET} (${size_human})" | |
| TOTAL_FREED=$((TOTAL_FREED + size_bytes)) | |
| CLEANED_COUNT=$((CLEANED_COUNT + 1)) | |
| else | |
| echo -ne " 🗑️ Removing: ${CYAN}$build_dir${RESET} (${size_human}) ... " | |
| if rm -rf "$build_dir" 2>/dev/null; then | |
| echo -e "${GREEN}done${RESET}" | |
| TOTAL_FREED=$((TOTAL_FREED + size_bytes)) | |
| CLEANED_COUNT=$((CLEANED_COUNT + 1)) | |
| else | |
| echo -e "${RED}failed${RESET}" | |
| SKIPPED_COUNT=$((SKIPPED_COUNT + 1)) | |
| fi | |
| fi | |
| done < <(find "$ROOT_DIR" -type d -name "build" \ | |
| ! -path "*/build/*/build" \ | |
| ! -path "*/.git/*" \ | |
| 2>/dev/null | sort) | |
| # ── Summary ────────────────────────────────────────────────── | |
| echo "" | |
| echo -e "${BOLD}─────────────────────────────────────────────────────${RESET}" | |
| if $DRY_RUN; then | |
| echo -e " ${YELLOW}[DRY RUN] Summary${RESET}" | |
| echo -e " Directories that would be removed : ${BOLD}$CLEANED_COUNT${RESET}" | |
| echo -e " Estimated space to be freed : ${BOLD}$(human_readable_size $TOTAL_FREED)${RESET}" | |
| else | |
| echo -e " ${GREEN}✅ Clean complete!${RESET}" | |
| echo -e " Directories removed : ${BOLD}$CLEANED_COUNT${RESET}" | |
| echo -e " Failed / skipped : ${BOLD}$SKIPPED_COUNT${RESET}" | |
| echo -e " Space freed : ${BOLD}$(human_readable_size $TOTAL_FREED)${RESET}" | |
| fi | |
| echo -e "${BOLD}─────────────────────────────────────────────────────${RESET}" | |
| echo "" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Examples!