Created
September 19, 2025 22:13
-
-
Save petenelson/18af8599e63090c031e47f6cb0bb4eb1 to your computer and use it in GitHub Desktop.
Delete directories that start with YYYY-MM-DD with dates earlier than today
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 | |
| # Script to delete directories with date prefixes older than current date | |
| # Usage: ./cleanup_dated_dirs.sh [--dry-run] [directory_path] | |
| # Default values | |
| DRY_RUN=false | |
| TARGET_DIR="." | |
| # Parse command line arguments | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| --dry-run) | |
| DRY_RUN=true | |
| shift | |
| ;; | |
| -h|--help) | |
| echo "Usage: $0 [--dry-run] [directory_path]" | |
| echo "" | |
| echo "Options:" | |
| echo " --dry-run Show what would be deleted without actually deleting" | |
| echo " -h, --help Show this help message" | |
| echo "" | |
| echo "Arguments:" | |
| echo " directory_path Directory to scan (default: current directory)" | |
| echo "" | |
| echo "Example:" | |
| echo " $0 --dry-run /path/to/logs" | |
| exit 0 | |
| ;; | |
| *) | |
| TARGET_DIR="$1" | |
| shift | |
| ;; | |
| esac | |
| done | |
| # Check if target directory exists | |
| if [[ ! -d "$TARGET_DIR" ]]; then | |
| echo "Error: Directory '$TARGET_DIR' does not exist" | |
| exit 1 | |
| fi | |
| # Get current date in YYYY-MM-DD format | |
| CURRENT_DATE=$(date +%Y-%m-%d) | |
| echo "Current date: $CURRENT_DATE" | |
| echo "Target directory: $TARGET_DIR" | |
| if [[ "$DRY_RUN" == true ]]; then | |
| echo "*** DRY RUN MODE - No directories will be deleted ***" | |
| fi | |
| echo "" | |
| # Counters | |
| deleted_count=0 | |
| skipped_count=0 | |
| # Function to check if a string is a valid date in YYYY-MM-DD format | |
| is_valid_date() { | |
| local date_str="$1" | |
| echo " Validating date: '$date_str'" | |
| # Check format with regex | |
| if [[ ! "$date_str" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then | |
| echo " Date format invalid (not YYYY-MM-DD)" | |
| return 1 | |
| fi | |
| echo " Date format valid, checking if date exists..." | |
| # Extract year, month, day | |
| local year="${date_str:0:4}" | |
| local month="${date_str:5:2}" | |
| local day="${date_str:8:2}" | |
| echo " Parsed: year=$year, month=$month, day=$day" | |
| # Basic range checks | |
| if [[ $month -lt 1 || $month -gt 12 ]]; then | |
| echo " Invalid month: $month" | |
| return 1 | |
| fi | |
| if [[ $day -lt 1 || $day -gt 31 ]]; then | |
| echo " Invalid day: $day" | |
| return 1 | |
| fi | |
| # Try multiple date command formats for compatibility | |
| local date_error="" | |
| # Try GNU date format first | |
| if date -d "$date_str" >/dev/null 2>&1; then | |
| echo " Date is valid (GNU date)" | |
| return 0 | |
| fi | |
| # Try BSD date format | |
| if date -j -f "%Y-%m-%d" "$date_str" >/dev/null 2>&1; then | |
| echo " Date is valid (BSD date)" | |
| return 0 | |
| fi | |
| # If both fail, capture the error for debugging | |
| date_error=$(date -d "$date_str" 2>&1) | |
| echo " Date validation failed. Error: $date_error" | |
| # For basic validation, if month and day are in reasonable ranges, accept it | |
| # This is a fallback for systems with problematic date commands | |
| if [[ $month -ge 1 && $month -le 12 && $day -ge 1 && $day -le 31 ]]; then | |
| echo " Using fallback validation - date appears valid" | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| # Function to compare dates (returns 0 if date1 < date2) | |
| is_date_older() { | |
| local date1="$1" | |
| local date2="$2" | |
| echo " Comparing dates: '$date1' vs '$date2'" | |
| # Try GNU date first | |
| local date1_epoch=$(date -d "$date1" +%s 2>/dev/null) | |
| local date2_epoch=$(date -d "$date2" +%s 2>/dev/null) | |
| # If GNU date failed, try BSD date | |
| if [[ -z "$date1_epoch" ]]; then | |
| date1_epoch=$(date -j -f "%Y-%m-%d" "$date1" +%s 2>/dev/null) | |
| fi | |
| if [[ -z "$date2_epoch" ]]; then | |
| date2_epoch=$(date -j -f "%Y-%m-%d" "$date2" +%s 2>/dev/null) | |
| fi | |
| # If date commands still fail, do string comparison as fallback | |
| if [[ -z "$date1_epoch" || -z "$date2_epoch" ]]; then | |
| echo " Using string comparison fallback" | |
| if [[ "$date1" < "$date2" ]]; then | |
| echo " $date1 is older than $date2 (string comparison)" | |
| return 0 | |
| else | |
| echo " $date1 is not older than $date2 (string comparison)" | |
| return 1 | |
| fi | |
| fi | |
| echo " Epochs: $date1_epoch vs $date2_epoch" | |
| if [[ $date1_epoch -lt $date2_epoch ]]; then | |
| echo " $date1 is older than $date2" | |
| return 0 # date1 is older | |
| else | |
| echo " $date1 is not older than $date2" | |
| return 1 # date1 is not older | |
| fi | |
| } | |
| # Process directories | |
| for dir in "$TARGET_DIR"/*/; do | |
| # Remove trailing slash and get just the directory name | |
| dir_path="${dir%/}" | |
| dir_name=$(basename "$dir_path") | |
| # Debug output | |
| echo "Processing: '$dir_name'" | |
| # Skip if not a directory (shouldn't happen with */ glob, but be safe) | |
| if [[ ! -d "$dir_path" ]]; then | |
| continue | |
| fi | |
| # Extract potential date prefix (first 10 characters) | |
| if [[ ${#dir_name} -ge 10 ]]; then | |
| potential_date="${dir_name:0:10}" | |
| echo " Checking first 10 chars: '$potential_date'" | |
| else | |
| potential_date="" | |
| echo " Directory name too short for date prefix" | |
| fi | |
| # Check if directory name starts with a valid date | |
| if [[ -n "$potential_date" ]] && is_valid_date "$potential_date"; then | |
| echo " Found valid dated directory: $dir_name (date: $potential_date)" | |
| # Check if the date is older than current date | |
| if is_date_older "$potential_date" "$CURRENT_DATE"; then | |
| if [[ "$DRY_RUN" == true ]]; then | |
| echo " [DRY RUN] Would delete: $dir_path" | |
| else | |
| echo " Deleting: $dir_path" | |
| if rm -rf "$dir_path"; then | |
| echo " Successfully deleted: $dir_path" | |
| else | |
| echo " Error: Failed to delete $dir_path" | |
| continue | |
| fi | |
| fi | |
| ((deleted_count++)) | |
| else | |
| echo " Skipping (date is current or future): $dir_path" | |
| ((skipped_count++)) | |
| fi | |
| else | |
| echo " Skipping non-dated directory: $dir_name" | |
| ((skipped_count++)) | |
| fi | |
| done | |
| # Summary | |
| echo "" | |
| echo "=== Summary ===" | |
| if [[ "$DRY_RUN" == true ]]; then | |
| echo "Directories that would be deleted: $deleted_count" | |
| else | |
| echo "Directories deleted: $deleted_count" | |
| fi | |
| echo "Directories skipped: $skipped_count" | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment