#!/bin/bash VERSION=$(date -r "$0" '+%Y-%m-%d') depth="-maxdepth 1" dry_run="" while [ $# -gt 0 ]; do case "$1" in -r|--recursive) depth="" ;; -n|--dry-run) dry_run=1 ;; -h|--help) echo "Usage: $(basename "$0") [-r] [-n]" echo " -r, --recursive search subdirectories too" echo " -n, --dry-run show what would be removed without deleting" exit 0 ;; *) echo "Unknown option: $1" >&2 exit 1 ;; esac shift done # colors YEL=$'\033[1;33m' BLU=$'\033[1;34m' CYN=$'\033[1;36m' WHT=$'\033[1;37m' DIM=$'\033[2;37m' RED=$'\033[1;31m' RST=$'\033[0m' progress_bar() { local current=$1 local total=$2 local width=36 local pct filled if [ "$total" -eq 0 ]; then pct=100; filled=$width else pct=$((current * 100 / total)) filled=$((current * width / total)) fi local empty=$((width - filled)) # Pac-Man mouth alternates open/closed local pac if (( current % 2 == 0 )); then pac="${YEL}ᗧ${RST}"; else pac="${YEL}ᗤ${RST}"; fi # eaten section: yellow dots local eaten="" if (( filled > 0 )); then eaten="${YEL}" for (( i=0; i 0 )); then local ghost_positions=() if (( empty >= 6 )); then ghost_positions+=( $((empty / 3)) ); fi if (( empty >= 12 )); then ghost_positions+=( $((empty * 2 / 3)) ); fi ahead="${DIM}" for (( i=0; i&2 } printf "${YEL}ᗧ··ᗤ${RST} ${WHT}dedupe${RST} ${DIM}v${VERSION}${RST}\n" >&2 printf "${DIM} scanning...${RST}" >&2 total_files=$(find . $depth -type f | wc -l | tr -d ' ') printf "\r${YEL}ᗧ${RST} Hashing ${WHT}%d${RST} files...\n" "$total_files" >&2 count=0 find . $depth -type f | while IFS= read -r file; do count=$((count + 1)) progress_bar "$count" "$total_files" md5sum "$file" done | sort | awk -v dry_run="${dry_run:-0}" ' BEGIN { first = 1; total = 0 } $1 != prev && prev != "" { count = 0 for (i = 0; i < n; i++) if (i != keep) count++ if (count > 0) { if (dry_run && !first) print "" first = 0 for (i = 0; i < n; i++) if (i != keep) print f[i] } total += count n = 0; keep = 0 } { fn = substr($0, 35) f[n++] = fn if ((fn ~ /schmeeve-AI-/ && f[keep] !~ /schmeeve-AI-/) || (fn !~ /\/ComfyUI/ && f[keep] ~ /\/ComfyUI/)) keep = n - 1 prev = $1 } END { count = 0 for (i = 0; i < n; i++) if (i != keep) count++ if (count > 0) { if (dry_run && !first) print "" for (i = 0; i < n; i++) if (i != keep) print f[i] } total += count if (dry_run) printf "Summary: %d duplicate file(s) found\n", total else printf "Removed %d duplicate file(s)\n", total > "/dev/stderr" }' | if [ -n "$dry_run" ]; then cat else while IFS= read -r f; do rm -f "$f" 2>/dev/null; done fi printf "\n" >&2