Synology/Linux : comparaison de fichiers par nom, taille, checksum (MD5)

cheksum 9 nov. 2015

Je possède quelques NAS Synology et fais malheureusement parti de ceux qui plus ils ont de place plus ils stockent (de bordel). Du coup afin de libérer un peu de place j’ai entrepris de fouiller dans mes films de vacances histoire de voir si j’en ai en double voire triple exemplaires.

En effet entre les différents nommages de fichiers à la source, les logiciels qui renomment, ou non, ma manie de cliquer un peu partout, d’utiliser différents outils de DL etc, ça devient un bon gros boxon et je vois assez souvent Kodi me lister au moins 2 versions d’un même film.

Du coup, vu mon espace de stockage, j’avais 2 solutions :

  • Poser 1 semaine de congés pour ne faire que çà,
  • L’automatiser, en partie du moins. J’ai retenu cette solution  \o/

 

J’ai trouvé un script réalisé par Vermaden, pour Linux, BSD et Sun, qui permet de comparer (lister et/ou effacer) des fichiers par nom, taille et checksum (MD5).

Je l’ai juste modifié au niveau de la description afin de la mettre en français et d’y ajouter une note pour le rendre très facilement compatible avec un NAS Synology. Ces NAS sont basés sur Linux mais ne comportent pas tous les logiciels d’une distribution normale, entre autre ils n’ont pas md5sum mais cksum.

 

Fonctionnement

Selon l’option choisie il va se contenter de lister les fichiers similaires ou alors afficher aussi une commande pour supprimer les doublons.

  • -n : comparaison par nom (rapide)
  • -s comparaison par taille (normale)
  • -m comparaison par checkum (lent voire très lent)
  • -N, -S, -M idem que les autres mais avec instructions pour effacer les fichiers

Ensuite il suffit simple d’indiquer au script sur quel dossier s’exécuter /home ou /mnt/images pour par exemple viser un dossier d’images monté en local. Du coup ça vous donnera une commande de ce type DupCheck.sh -n /mnt/images pour comparer les images par leurs noms.

 

Exécution sur PC/serveur

Il suffit de créer un fichier script, par exemple DupCheck.sh et d’y coller le code. Puis lancer la commande avec l’option désirée sur le dossier cible, comme vu au-dessus.

 

Exécution sur Synology

Il faut déposer le script sur le NAS ou alors le créer directement dessus via l’outil Editeur de texte. Il faut bien entendu nommer le fichier en .sh afin qu’il soit reconnu comme un script. Il convient de changer une variable dedans, ligne 51, MD5="md5sum" devant devenir MD5="cksum" pour une question de compatibilité.

Et il peut ensuite être exécuté sur le NAS depuis un PC via SSH ou directement depuis le NAS par exemple via WebConsole.

 

Source

#! /bin/sh

# find duplicated files in directory tree
# comparing by file NAME, SIZE or MD5 checksum
# --------------------------------------------
# LICENSE(s): BSD / CDDL
# --------------------------------------------
# vermaden [AT] interia [DOT] pl
# http://strony.toya.net.pl/~vermaden/links.htm
#
# French Translation & Synology tip by Aerya
# https://upandclear.org/

__usage() {
  echo "**Script de comparaison de fichiers dans un même dossier**"
  echo ""
  echo "Utilisation : $( basename ${0} ) OPTION DOSSIER"
  echo ""
  echo "Options :   -n   (Rapide)  par nom"
  echo "            -s   (Normale) par taille"
  echo "            -m   (Lente)   par signature (https://fr.wikipedia.org/wiki/MD5)" 
  echo "            -N             '-n' mais avec instructions pour effacer"
  echo "            -S             '-s' mais avec instructions pour effacer"
  echo "            -M             '-m' mais avec instructions pour effacer"
  echo ""
  echo "Exemple : $( basename ${0} ) -s /home"
  echo ""
  echo "Pour s'en servir sur Synology, si vous ne voulez pas y installer MD5SUM, éditez le script et mettez 'MD5="cksum"' à la place de 'MD5="md5sum"' ligne 42"
  echo ""
  exit 1
  }

__prefix() {
  case $( id -u ) in
    (0) PREFIX="rm -rf" ;;
    (*) case $( uname ) in
          (SunOS) PREFIX="pfexec rm -rf" ;;
          (*)     PREFIX="sudo rm -rf"   ;;
        esac
        ;;
  esac
  }

__crossplatform() {
  case $( uname ) in
    (FreeBSD)
      MD5="md5 -r"
      STAT="stat -f %z"
      ;;
    (Linux)
      MD5="md5sum"
      STAT="stat -c %s"
      ;;
    (SunOS)
      echo "INFO: supported systems: FreeBSD Linux"
      echo
      echo "Porting to Solaris/OpenSolaris"
      echo "  -- provide values for MD5/STAT in '$( basename ${0} ):__crossplatform()'"
      echo "  -- use digest(1) instead for md5 sum calculation"
      echo "       $ digest -a md5 file"
      echo "  -- pfexec(1) is already used in '$( basename ${0} ):__prefix()'"
      echo
      exit 1
    (*)
      echo "INFO: supported systems: FreeBSD Linux"
      exit 1
      ;;
  esac
  }

__md5() {
  __crossplatform
  :> ${DUPLICATES_FILE}
  DATA=$( find "${1}" -type f -exec ${MD5} {} ';' | sort -n )
  echo "${DATA}" \
    | awk '{print $1}' \
    | uniq -c \
    | while read LINE
      do
        COUNT=$( echo ${LINE} | awk '{print $1}' )
        [ ${COUNT} -eq 1 ] && continue
        SUM=$( echo ${LINE} | awk '{print $2}' )
        echo "${DATA}" | grep ${SUM} >> ${DUPLICATES_FILE}
      done

  echo "${DATA}" \
    | awk '{print $1}' \
    | sort -n \
    | uniq -c \
    | while read LINE
      do
        COUNT=$( echo ${LINE} | awk '{print $1}' )
        [ ${COUNT} -eq 1 ] && continue
        SUM=$( echo ${LINE} | awk '{print $2}' )
        echo "count: ${COUNT} | md5: ${SUM}"
        grep ${SUM} ${DUPLICATES_FILE} \
          | cut -d ' ' -f 2-10000 2> /dev/null \
          | while read LINE
            do
              if [ -n "${PREFIX}" ]
              then
                echo "  ${PREFIX} \"${LINE}\""
              else
                echo "  ${LINE}"
              fi
            done
        echo
      done
  rm -rf ${DUPLICATES_FILE}
  }

__size() {
  __crossplatform
  find "${1}" -type f -exec ${STAT} {} ';' \
    | sort -n \
    | uniq -c \
    | while read LINE
      do
        COUNT=$( echo ${LINE} | awk '{print $1}' )
        [ ${COUNT} -eq 1 ] && continue
        SIZE=$( echo ${LINE} | awk '{print $2}' )
        SIZE_KB=$( echo ${SIZE} / 1024 | bc )
        echo "count: ${COUNT} | size: ${SIZE_KB}KB (${SIZE} bytes)"
        if [ -n "${PREFIX}" ]
        then
          find ${1} -type f -size ${SIZE}c -exec echo "  ${PREFIX} \"{}\"" ';'
        else
          # find ${1} -type f -size ${SIZE}c -exec echo "  {}  " ';'  -exec du -h "  {}" ';'
          find ${1} -type f -size ${SIZE}c -exec echo "  {}  " ';'
        fi
        echo
      done
  }

__file() {
  __crossplatform
  find "${1}" -type f \
    | xargs -n 1 basename 2> /dev/null \
    | tr '[A-Z]' '[a-z]' \
    | sort -n \
    | uniq -c \
    | sort -n -r \
    | while read LINE
      do
        COUNT=$( echo ${LINE} | awk '{print $1}' )
        [ ${COUNT} -eq 1 ] && break
        FILE=$( echo ${LINE} | cut -d ' ' -f 2-10000 2> /dev/null )
        echo "count: ${COUNT} | file: ${FILE}"
        FILE=$( echo ${FILE} | sed -e s/'\['/'\\\['/g -e s/'\]'/'\\\]'/g )
        if [ -n "${PREFIX}" ]
        then
          find ${1} -iname "${FILE}" -exec echo "  ${PREFIX} \"{}\"" ';'
        else
          find ${1} -iname "${FILE}" -exec echo "  {}" ';'
        fi
        echo
      done 
  }

# main()

[ ${#} -ne 2  ] && __usage
[ ! -d "${2}" ] && __usage

DUPLICATES_FILE="/tmp/$( basename ${0} )_DUPLICATES_FILE.tmp"

case ${1} in
  (-n)           __file "${2}" ;;
  (-m)           __md5  "${2}" ;;
  (-s)           __size "${2}" ;;
  (-N) __prefix; __file "${2}" ;;
  (-M) __prefix; __md5  "${2}" ;;
  (-S) __prefix; __size "${2}" ;;
  (*)  __usage ;;
esac

 

Mots clés