diff --git a/file-cleaning.sh b/file-cleaning.sh new file mode 100644 index 0000000..b73d968 --- /dev/null +++ b/file-cleaning.sh @@ -0,0 +1,307 @@ +#!/bin/bash + +# Log and GZ File Cleaner Script +# Removes all .log and .gz files from specified directories + +# Function to display usage +show_usage() { + echo "Usage: $0 [OPTIONS] [directory2] [directory3] ..." + echo "" + echo "Options:" + echo " -r, --recursive Clean files recursively in subdirectories (DEFAULT)" + echo " -s, --surface-only Only clean files in specified directory (no subdirs)" + echo " -i, --interactive Ask before deleting each file" + echo " -v, --verbose Show detailed output" + echo " -n, --dry-run Show what would be deleted without actually deleting" + echo " -f, --force Force deletion without prompts" + echo " -o, --old-only DAYS Only delete files older than specified days" + echo " -z, --size-only SIZE Only delete files larger than specified size (e.g., 10M, 1G)" + echo " -h, --help Show this help message" + echo "" + echo "Examples:" + echo " $0 /var/log # Clean all subdirectories" + echo " $0 --surface-only /var/log # Clean only /var/log (no subdirs)" + echo " $0 --dry-run /var/log # Show what would be deleted" + echo " $0 --old-only 7 /var/log # Only files older than 7 days" + echo " $0 --size-only 100M /var/log # Only files larger than 100MB" + echo "" + echo "File types cleaned: *.log, *.gz" +} + +# Default options +RECURSIVE=true +INTERACTIVE=false +VERBOSE=false +DRY_RUN=false +FORCE=false +OLD_ONLY_DAYS="" +SIZE_ONLY="" +DIRECTORIES=() + +# Counters +TOTAL_FILES=0 +TOTAL_SIZE=0 +DELETED_FILES=0 +DELETED_SIZE=0 + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + -r|--recursive) + RECURSIVE=true + shift + ;; + -s|--surface-only) + RECURSIVE=false + shift + ;; + -i|--interactive) + INTERACTIVE=true + shift + ;; + -v|--verbose) + VERBOSE=true + shift + ;; + -n|--dry-run) + DRY_RUN=true + shift + ;; + -f|--force) + FORCE=true + shift + ;; + -o|--old-only) + OLD_ONLY_DAYS="$2" + shift 2 + ;; + -z|--size-only) + SIZE_ONLY="$2" + shift 2 + ;; + -h|--help) + show_usage + exit 0 + ;; + -*) + echo "Unknown option: $1" + show_usage + exit 1 + ;; + *) + DIRECTORIES+=("$1") + shift + ;; + esac +done + +# Check if directories are provided +if [ ${#DIRECTORIES[@]} -eq 0 ]; then + echo "Error: At least one directory must be specified" + show_usage + exit 1 +fi + +# Validate old-only days parameter +if [ -n "$OLD_ONLY_DAYS" ] && ! [[ "$OLD_ONLY_DAYS" =~ ^[0-9]+$ ]]; then + echo "Error: --old-only parameter must be a positive number" + exit 1 +fi + +# Function to convert size to bytes +size_to_bytes() { + local size="$1" + local num=$(echo "$size" | sed 's/[^0-9]//g') + local unit=$(echo "$size" | sed 's/[0-9]//g' | tr '[:lower:]' '[:upper:]') + + # Convert to integer (remove decimal part if present) + num=${num%%.*} + + case "$unit" in + "K"|"KB") echo $((num * 1024)) ;; + "M"|"MB") echo $((num * 1024 * 1024)) ;; + "G"|"GB") echo $((num * 1024 * 1024 * 1024)) ;; + "") echo "$num" ;; + *) echo "0" ;; + esac +} + +# Function to format file size +format_size() { + local bytes=$1 + if [ $bytes -lt 1024 ]; then + echo "${bytes}B" + elif [ $bytes -lt 1048576 ]; then + echo "$((bytes / 1024))K" + elif [ $bytes -lt 1073741824 ]; then + echo "$((bytes / 1048576))M" + else + echo "$((bytes / 1073741824))G" + fi +} + +# Function to check if file meets criteria +meets_criteria() { + local file="$1" + local file_size=$(stat -c%s "$file" 2>/dev/null || echo "0") + local file_age_days="" + + # Check age criteria + if [ -n "$OLD_ONLY_DAYS" ]; then + file_age_days=$(find "$file" -mtime +$OLD_ONLY_DAYS -print | wc -l) + if [ "$file_age_days" -eq 0 ]; then + return 1 + fi + fi + + # Check size criteria + if [ -n "$SIZE_ONLY" ]; then + local min_size=$(size_to_bytes "$SIZE_ONLY") + if [ "$file_size" -lt "$min_size" ]; then + return 1 + fi + fi + + return 0 +} + +# Function to process a single file +process_file() { + local file="$1" + local file_size=$(stat -c%s "$file" 2>/dev/null || echo "0") + local formatted_size=$(format_size $file_size) + + ((TOTAL_FILES++)) + TOTAL_SIZE=$((TOTAL_SIZE + file_size)) + + # Check if file meets criteria + if ! meets_criteria "$file"; then + if [ "$VERBOSE" = true ]; then + echo " SKIP: $file (doesn't meet criteria)" + fi + return + fi + + if [ "$DRY_RUN" = true ]; then + echo " WOULD DELETE: $file ($formatted_size)" + ((DELETED_FILES++)) + DELETED_SIZE=$((DELETED_SIZE + file_size)) + return + fi + + # Interactive mode + if [ "$INTERACTIVE" = true ] && [ "$FORCE" = false ]; then + echo -n "Delete $file ($formatted_size)? [y/N] " + read -r response + if [[ ! "$response" =~ ^[Yy]$ ]]; then + if [ "$VERBOSE" = true ]; then + echo " SKIP: $file (user declined)" + fi + return + fi + fi + + # Delete the file + if rm -f "$file" 2>/dev/null; then + if [ "$VERBOSE" = true ]; then + echo " DELETED: $file ($formatted_size)" + fi + ((DELETED_FILES++)) + DELETED_SIZE=$((DELETED_SIZE + file_size)) + else + echo " ERROR: Failed to delete $file" + fi +} + +# Function to clean a directory +clean_directory() { + local dir="$1" + + if [ ! -d "$dir" ]; then + echo "Warning: Directory '$dir' does not exist" + return + fi + + if [ ! -r "$dir" ]; then + echo "Warning: Directory '$dir' is not readable" + return + fi + + echo "Cleaning directory: $dir" + + # Build find command (always recursive by default) + local find_cmd="find \"$dir\" -type f \\( -name \"*.log\" -o -name \"*.gz\" \\)" + + # Only add maxdepth if surface-only mode is explicitly requested + if [ "$RECURSIVE" = false ]; then + find_cmd="find \"$dir\" -maxdepth 1 -type f \\( -name \"*.log\" -o -name \"*.gz\" \\)" + fi + + # Execute find and process files + local files=() + while IFS= read -r -d '' file; do + files+=("$file") + done < <(eval "$find_cmd -print0" 2>/dev/null) + + if [ ${#files[@]} -eq 0 ]; then + echo " No log or gz files found" + return + fi + + echo " Found ${#files[@]} files to process" + + # Process each file + for file in "${files[@]}"; do + process_file "$file" + done +} + +# Main execution +echo "Log and GZ File Cleaner" +echo "=======================" + +if [ "$DRY_RUN" = true ]; then + echo "DRY RUN MODE - No files will be deleted" +fi + +if [ -n "$OLD_ONLY_DAYS" ]; then + echo "Only processing files older than $OLD_ONLY_DAYS days" +fi + +if [ -n "$SIZE_ONLY" ]; then + echo "Only processing files larger than $SIZE_ONLY" +fi + +if [ "$RECURSIVE" = true ]; then + echo "Recursive mode enabled (cleaning all subdirectories)" +else + echo "Surface-only mode (cleaning specified directories only)" +fi + +echo "" + +# Process each directory +for dir in "${DIRECTORIES[@]}"; do + clean_directory "$dir" + echo "" +done + +# Summary +echo "Summary:" +echo "========" +echo "Total files found: $TOTAL_FILES" +echo "Total size found: $(format_size $TOTAL_SIZE)" + +if [ "$DRY_RUN" = true ]; then + echo "Files that would be deleted: $DELETED_FILES" + echo "Space that would be freed: $(format_size $DELETED_SIZE)" +else + echo "Files deleted: $DELETED_FILES" + echo "Space freed: $(format_size $DELETED_SIZE)" +fi + +if [ "$DELETED_FILES" -gt 0 ] || [ "$DRY_RUN" = true ]; then + exit 0 +else + exit 1 +fi