Skip to content

feat: provide method for cleaning out root module folders #17

@westonplatter

Description

@westonplatter

When using this for 10+ root-modules, I found I had GBs of .terraform folders. I think we want to help users have a simple approach for trimming down.terraform root-modules as someone's 256GB hard drive fills up.

Image

Here's a v1 script that I came up with using Claude Code.

#!/bin/bash

# Terraform Cleanup Script
# This script finds and allows deletion of .terraform folders

set -e

echo "=================================="
echo "   TERRAFORM FOLDER CLEANUP"
echo "=================================="
echo ""

# Get the path to scan (default to HOME if not provided)
SCAN_PATH="${1:-$HOME}"

# Validate the path exists
if [ ! -d "$SCAN_PATH" ]; then
    echo "ERROR: Path '$SCAN_PATH' does not exist or is not a directory."
    exit 1
fi

# Convert to absolute path
SCAN_PATH=$(cd "$SCAN_PATH" && pwd)

echo "Scanning for .terraform folders in: $SCAN_PATH"
echo "This may take a moment..."
echo ""

# Show progress bar during scan
show_progress() {
    local pid=$1
    local delay=0.1
    local spinstr='|/-\'
    local bar_width=50
    local progress=0

    while kill -0 "$pid" 2>/dev/null; do
        # Calculate progress (oscillate between 0-100 since we don't know real progress)
        local pos=$((progress % (bar_width * 2)))
        if [ $pos -ge $bar_width ]; then
            pos=$((bar_width * 2 - pos))
        fi

        # Build progress bar
        printf "\r["
        for ((i=0; i<bar_width; i++)); do
            if [ $i -eq $pos ]; then
                printf "="
            else
                printf " "
            fi
        done
        printf "] Scanning..."

        progress=$((progress + 1))
        sleep $delay
    done

    # Clear the progress bar line
    printf "\r%*s\r" $((bar_width + 15)) ""
}

# Find all .terraform directories (compatible with bash 3.x)
TERRAFORM_DIRS=()
TEMP_FILE=$(mktemp)

# Run find in background and show progress
find "$SCAN_PATH" -type d -name ".terraform" 2>/dev/null > "$TEMP_FILE" &
FIND_PID=$!
show_progress $FIND_PID
wait $FIND_PID

# Read results from temp file
while IFS= read -r dir; do
    TERRAFORM_DIRS+=("$dir")
done < "$TEMP_FILE"
rm -f "$TEMP_FILE"

# Check if any were found
if [ ${#TERRAFORM_DIRS[@]} -eq 0 ]; then
    echo "No .terraform folders found in $SCAN_PATH"
    exit 0
fi

echo "Found ${#TERRAFORM_DIRS[@]} .terraform folder(s):"
echo "-------------------------------------------"

# Create temporary file to store directory sizes in bytes for sorting
TEMP_SIZES=$(mktemp)

# Get sizes in bytes for sorting
for dir in "${TERRAFORM_DIRS[@]}"; do
    size_bytes=$(du -sk "$dir" 2>/dev/null | cut -f1)
    echo "$size_bytes|$dir" >> "$TEMP_SIZES"
done

# Sort by size (largest first) and rebuild arrays
SORTED_TERRAFORM_DIRS=()
declare -a SIZES

while IFS='|' read -r size_bytes dir; do
    SORTED_TERRAFORM_DIRS+=("$dir")
    # Convert back to human-readable format for display
    size=$(du -sh "$dir" 2>/dev/null | cut -f1)
    SIZES+=("$size")
done < <(sort -rn "$TEMP_SIZES")

rm -f "$TEMP_SIZES"

# Replace original array with sorted array
TERRAFORM_DIRS=("${SORTED_TERRAFORM_DIRS[@]}")

# Display all found folders with sizes (now sorted)
for i in "${!TERRAFORM_DIRS[@]}"; do
    printf "%3d. [%8s] %s\n" $((i+1)) "${SIZES[$i]}" "${TERRAFORM_DIRS[$i]}"
done

echo ""

# Calculate total size
TOTAL_SIZE=$(du -shc "${TERRAFORM_DIRS[@]}" 2>/dev/null | tail -1 | cut -f1)
echo "Total size: $TOTAL_SIZE"
echo ""

# Main menu
while true; do
    echo "What would you like to do?"
    echo "  1) Select individual folders to delete"
    echo "  2) Delete all .terraform folders"
    echo "  3) Delete none (exit)"
    echo ""
    read -p "Enter your choice (1-3 or 'exit'): " choice

    # Check for exit command
    if [[ "$choice" == "exit" ]]; then
        echo "Exiting. No changes made."
        exit 0
    fi

    case $choice in
        1)
            # Select individually
            echo ""
            echo "Enter the numbers of folders to delete (space-separated)."
            echo "Example: 1 3 5"
            echo ""
            read -p "Folder numbers: " -a selections

            FOLDERS_TO_DELETE=()
            for num in "${selections[@]}"; do
                # Validate number
                if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le ${#TERRAFORM_DIRS[@]} ]; then
                    idx=$((num-1))
                    FOLDERS_TO_DELETE+=("${TERRAFORM_DIRS[$idx]}")
                else
                    echo "Warning: Invalid selection '$num' - skipping"
                fi
            done

            if [ ${#FOLDERS_TO_DELETE[@]} -eq 0 ]; then
                echo "No valid folders selected. Exiting."
                exit 0
            fi
            break
            ;;
        2)
            # Delete all
            FOLDERS_TO_DELETE=("${TERRAFORM_DIRS[@]}")
            break
            ;;
        3)
            # Exit
            echo "No folders will be deleted. Exiting."
            exit 0
            ;;
        *)
            echo "Invalid choice. Please enter 1, 2, 3, or 'exit'."
            echo ""
            ;;
    esac
done

# Show what will be deleted
echo ""
echo "=================================="
echo "FOLDERS TO BE DELETED:"
echo "=================================="
for dir in "${FOLDERS_TO_DELETE[@]}"; do
    # Find the size for this directory
    for i in "${!TERRAFORM_DIRS[@]}"; do
        if [ "${TERRAFORM_DIRS[$i]}" = "$dir" ]; then
            printf "[%8s] %s\n" "${SIZES[$i]}" "$dir"
            break
        fi
    done
done

# Calculate size of folders to delete
DELETE_SIZE=$(du -shc "${FOLDERS_TO_DELETE[@]}" 2>/dev/null | tail -1 | cut -f1)
echo ""
echo "Total size to be freed: $DELETE_SIZE"
echo ""

# Final confirmation
read -p "Are you sure you want to delete ${#FOLDERS_TO_DELETE[@]} folder(s)? [N/yes]: " confirmation

# Default to "no" if empty or anything other than "yes"
if [[ "$confirmation" != "yes" ]]; then
    echo "Deletion cancelled. No changes made."
    exit 0
fi

# Perform deletion
echo ""
echo "Deleting folders..."
DELETED_COUNT=0
FAILED_COUNT=0

for dir in "${FOLDERS_TO_DELETE[@]}"; do
    if rm -rf "$dir" 2>/dev/null; then
        echo "✓ Deleted: $dir"
        ((DELETED_COUNT++))
    else
        echo "✗ Failed to delete: $dir"
        ((FAILED_COUNT++))
    fi
done

echo ""
echo "=================================="
echo "CLEANUP COMPLETE"
echo "=================================="
echo "Deleted: $DELETED_COUNT folder(s)"
if [ $FAILED_COUNT -gt 0 ]; then
    echo "Failed: $FAILED_COUNT folder(s)"
fi
echo "Space freed: ~$DELETE_SIZE"
echo ""

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions