308 lines
7.8 KiB
Bash
308 lines
7.8 KiB
Bash
#!/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] <directory> [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
|