Introducción
Lo vamos a hacer en 2 pasos:
- Detectaremos duplicados por nombre y tamaño (excluyendo algunas carpetas y extensiones de ficheros) creando un fichero con la lista de duplicados
- Copiaremos los ficheros excluyendo los ficheros de la lista guadada en el fichero generado anteriormente y las carpetas y ficheros excluidos por extensión
1. Generar una lista de ficheros duplicados:
- Las líneas 35 a 39 indican las carpetas a excluir
- Las lÍneas 42 a 44 indica las extensiones de ficheros a excluir
- Al final nos da el nombre del fichero generado
- Para ejecutar el script hay que pasarle la carpeta a analizar
Ejecutamos este script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #!/bin/bash # buscar_duplicados_exacto_final.sh # Autor: Ximo Dante con IA # Busca archivos con el mismo nombre y tamaño exacto, # excluyendo carpetas del sistema y archivos temporales. # Marca con "#" las cabeceras y el fichero más superficial. set -euo pipefail IFS=$'\n' BASE_DIR="${1:-}" if [[ -z "$BASE_DIR" ]]; then echo "❌ Uso: $0 /ruta/a/carpeta" exit 1 fi if [[ ! -d "$BASE_DIR" ]]; then echo "❌ No existe el directorio: $BASE_DIR" exit 1 fi TIMESTAMP=$(date +%Y%m%d_%H%M%S) OUT="duplicados_final_${TIMESTAMP}.txt" echo "🔍 Buscando duplicados exactos en: $BASE_DIR" echo "📝 Informe: $OUT" echo # ------------------------------------------------------------ # 1️⃣ Buscar y procesar con find + awk (sin bucles) # ------------------------------------------------------------ find "$BASE_DIR" \ \( -type d \( \ -name ".*" -o -name "\$*" \ -o -iname "Archivos de programa" -o -iname "Descargas" -o -iname "Downloads" \ -o -iname "Documents and Settings" -o -iname "Logs" -o -iname "PerfLogs" \ -o -iname "Program Files" -o -iname "Program Files (x86)" -o -iname "ProgramData" \ -o -iname "Recovery" -o -iname "System Volume Information" -o -iname "Temp" \ -o -iname "Users" -o -iname "Windows" -o -iname "Windows10Upgrade" \ \) -prune \) \ -o -type f \ ! -iname "*.exe" ! -iname "*.log" ! -iname "*.dll" ! -iname "*.sys"\ ! -iname "*.part" ! -iname "*.crdownload" ! -iname "*.tmp" \ ! -iname "*.partial" ! -iname "*.download" ! -iname "*!qB*" ! -iname "*.aria2" \ -printf '%f\t%s\t%p\n' 2>/dev/null \ | sort -k1,1 -k2,2n \ | awk -F'\t' -v base="$BASE_DIR" ' function depth(path, nf, nb, a, b) { nf = split(path, a, "/"); nb = split(base, b, "/"); return nf - nb - 1; } { name=$1; size=$2; path=$3; # Ignorar temporales (~$, _~, ~.) if (name ~ /^~[$]|^_~|^~\./) next; key = name "|" size; files[key] = files[key] ? files[key] RS path : path; } END { dup_groups=0; for (k in files) { n = split(files[k], arr, "\n"); if (n > 1) { dup_groups++; split(k, parts, "|"); print "#-----------------------------------"; print "#📂 Duplicado exacto: " parts[1] " (" parts[2] " bytes)"; # Fichero más superficial (menor profundidad) min_d=1e9; idx=0; for (i=1; i<=n; i++) { d = depth(arr[i]); depths[i]=d; if (d < min_d) { min_d=d; idx=i; } } for (i=1; i<=n; i++) { mark = (i==idx) ? "#" : " "; printf "%s%s [nivel=%d]\n", mark, arr[i], depths[i]; } } } if (dup_groups==0) print "ℹ️ No se encontraron duplicados exactos (nombre + tamaño)" > "/dev/stderr"; else print "✅ Se encontraron " dup_groups " grupos de duplicados." > "/dev/stderr"; } ' > "$OUT" echo if [[ -s "$OUT" ]]; then echo "✅ Informe generado: $(realpath "$OUT")" else echo "ℹ️ El fichero está vacío: no se detectaron duplicados exactos tras exclusiones." fi echo |
2. Copia de carpetas en base al fichero de duplicados:
- Las líneas 55 a 59 indican las carpetas a excluir
- Las lÍneas 62 a 64 indica las extensiones de ficheros a excluir
- Al final nos da el nombre del fichero generado con la lista de ficheros copiados
- Para ejecutar el script hay que pasarle las carpeta de origen y destino y la ruta del fichero de duplicados generados en el punto anterior
Veamos el script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | #!/bin/bash # ============================================================ # 🧰 copiar_no_duplicados.sh # Autor: Ximo Dante + IA # Copia solo los ficheros no duplicados ni excluidos # según el informe generado por buscar_duplicados_exacto_final.sh # Sin usar rsync — usa find + cp --parents (más estable) # ============================================================ set -euo pipefail IFS=$'\n' ORIGEN="${1:-}" DESTINO="${2:-}" DUP_FILE="${3:-}" if [[ -z "$ORIGEN" || -z "$DESTINO" || -z "$DUP_FILE" ]]; then echo "❌ Uso: $0 /carpeta/origen /carpeta/destino duplicados_final_xxx.txt" exit 1 fi if [[ ! -d "$ORIGEN" ]]; then echo "❌ Carpeta origen no existe: $ORIGEN" exit 1 fi if [[ ! -f "$DUP_FILE" ]]; then echo "❌ No existe el fichero de duplicados: $DUP_FILE" exit 1 fi mkdir -p "$DESTINO" TS=$(date +%Y%m%d_%H%M%S) LOG="$DESTINO/copiar_no_duplicados_${TS}.log" echo "📂 Carpeta origen: $ORIGEN" echo "📁 Carpeta destino: $DESTINO" echo "🧾 Archivo de duplicados: $DUP_FILE" echo "📝 Log: $LOG" echo # ------------------------------------------------------------ # 1️⃣ Construir lista de rutas a excluir # ------------------------------------------------------------ EXCL_TMP=$(mktemp) grep -v '^#' "$DUP_FILE" | grep -E '^/' > "$EXCL_TMP" || true # ------------------------------------------------------------ # 2️⃣ Encontrar archivos válidos (no duplicados ni excluidos) # ------------------------------------------------------------ echo "🔎 Escaneando archivos válidos..." find "$ORIGEN" \ \( -type d \( \ -name ".*" -o -name "\$*" \ -o -iname "Archivos de programa" -o -iname "Descargas" -o -iname "Downloads" \ -o -iname "Documents and Settings" -o -iname "Logs" -o -iname "PerfLogs" \ -o -iname "Program Files" -o -iname "Program Files (x86)" -o -iname "ProgramData" \ -o -iname "Recovery" -o -iname "System Volume Information" -o -iname "Temp" \ -o -iname "Users" -o -iname "Windows" -o -iname "Windows10Upgrade" \ \) -prune \) \ -o -type f \ ! -iname "*.exe" ! -iname "*.log" ! -iname "*.dll" ! -iname "*.sys" \ ! -iname "*.part" ! -iname "*.crdownload" ! -iname "*.tmp" \ ! -iname "*.partial" ! -iname "*.download" ! -iname "*!qB*" ! -iname "*.aria2" \ -print0 2>/dev/null \ | grep -zavFf "$EXCL_TMP" \ | tee >(xargs -0 -I{} bash -c ' FILE="{}" REL="${FILE#'"$ORIGEN"'/}" DEST_FILE="'"$DESTINO"'/$REL" mkdir -p "$(dirname "$DEST_FILE")" cp -p "$FILE" "$DEST_FILE" echo "✔ Copiado: $REL" >> "'"$LOG"'" ') > /dev/null # ------------------------------------------------------------ # 3️⃣ Mostrar resumen # ------------------------------------------------------------ COPIADOS=$(grep -c "✔ Copiado:" "$LOG" || echo 0) echo echo "✅ Copia completada." echo "📦 Archivos copiados: $COPIADOS" echo "📄 Log detallado: $LOG" echo |
No hay comentarios :
Publicar un comentario