add file-cleaning

This commit is contained in:
nnduc
2025-07-12 19:41:16 +07:00
parent 8ae6274806
commit 635ebbe5d5

307
file-cleaning.sh Normal file
View File

@ -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] <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