2 votes

Comment puis-je comparer deux répertoires de manière récursive et vérifier si l'un des répertoires contient l'autre ?

J'ai deux répertoires, ils contiennent des fichiers communs. Je veux savoir si un répertoire contient le même fichier que l'autre. J'ai trouvé un script sur le net mais je veux avoir besoin de l'améliorer pour faire récursivement.

  #!/bin/bash

  # cmp_dir - program to compare two directories

  # Check for required arguments
  if [ $# -ne 2 ]; then
      echo "usage: $0 directory_1 directory_2" 1>&2
      exit 1
  fi

  # Make sure both arguments are directories
  if [ ! -d $1 ]; then
      echo "$1 is not a directory!" 1>&2
      exit 1
  fi

  if [ ! -d $2 ]; then
      echo "$2 is not a directory!" 1>&2
      exit 1
  fi

  # Process each file in directory_1, comparing it to directory_2
  missing=0
  for filename in $1/*; do
      fn=$(basename "$filename")
      if [ -f "$filename" ]; then
          if [ ! -f "$2/$fn" ]; then
              echo "$fn is missing from $2"
              missing=$((missing + 1))
          fi
      fi
  done
  echo "$missing files missing"

Quelqu'un peut-il suggérer un algorithme pour cela ?

7voto

user221266 Points 11
#!/bin/bash

# cmp_dir - program to compare two directories

# Check for required arguments
if [ $# -ne 2 ]; then
  echo "usage: $0 directory_1 directory_2" 1>&2
  exit 1
fi

# Make sure both arguments are directories
if [ ! -d "$1" ]; then
  echo "$1 is not a directory!" 1>&2
  exit 1
fi

if [ ! -d "$2" ]; then
  echo "$2 is not a directory!" 1>&2
  exit 1
fi

# Process each file in directory_1, comparing it to directory_2
missing=0
while IFS= read -r -d $'\0' filename
do
  fn=${filename#$1}
  if [ ! -f "$2/$fn" ]; then
      echo "$fn is missing from $2"
      missing=$((missing + 1))
  fi
done < <(find "$1" -type f -print0)

echo "$missing files missing"

Notez que j'ai ajouté des guillemets autour de $1 y $2 à divers endroits au-dessus pour les protéger Shell expansion. Sans les doubles guillemets, les noms de répertoires contenant des espaces ou d'autres caractères difficiles provoqueraient des erreurs.

La boucle de clé se lit maintenant :

while IFS= read -r -d $'\0' filename
do
  fn=${filename#$1}
  if [ ! -f "$2/$fn" ]; then
      echo "$fn is missing from $2"
      missing=$((missing + 1))
  fi
done < <(find "$1" -type f -print0)

Cela utilise find pour plonger récursivement dans le répertoire $1 et trouver des noms de fichiers. La construction while IFS= read -r -d $'\0' filename; do .... done < <(find "$1" -type f -print0) est sûr contre tous les noms de fichiers.

basename n'est plus utilisé car nous regardons les fichiers dans les sous-répertoires et nous devons conserver les sous-répertoires. Ainsi, à la place de l'appel à basename la ligne fn=${filename#$1} est utilisé. Cela supprime simplement de filename le préfixe contenant le répertoire $1 .

Problème 2

Supposons que nous fassions correspondre les fichiers par nom mais sans tenir compte du répertoire. En d'autres termes, si le premier répertoire contient un fichier a/b/c/some.txt nous considérerons qu'il est présent dans le deuxième répertoire si le fichier some.txt existe dans n'importe quel sous-répertoire du deuxième répertoire. Pour ce faire, remplacez la boucle ci-dessus par :

while IFS= read -r -d $'\0' filename
do
  fn=$(basename "$filename")
  if ! find "$2" -name "$fn" | grep -q . ; then
      echo "$fn is missing from $2"
      missing=$((missing + 1))
  fi
done < <(find "$1" -type f -print0)

3voto

Enterprise Points 10450

FSlint est une petite application GUI qui vous aide à identifier et à nettoyer votre système des fichiers redondants.

Installation de FSlint

Installez FSlint à partir du Centre logiciel Ubuntu, ou à partir de la ligne de commande comme suit :

sudo apt-get install fslint

(Sur mon système, l'installation de FSlint n'a pas entraîné de dépendances supplémentaires. Plus précisément, FSlint dépend de findutils, Python, et Python-glade2, qui devraient tous être déjà sur votre système. Vous pouvez supprimer FSlint en utilisant le centre logiciel ou en tapant sudo apt-get autoremove --purge fslint dans un terminal).

Recherche de fichiers

Lancez FSlint à partir de l'Unity Dash.

Voici une capture d'écran de l'écran principal. Il existe de nombreuses fonctionnalités avancées, mais l'utilisation de base de l'application est relativement simple.

Cliquez sur le bouton Add en haut à gauche pour ajouter tous les répertoires que vous souhaitez vérifier. Évidemment, vous pouvez supprimer des répertoires en utilisant le bouton Remove bouton.

enter image description here

Assurez-vous que le recurse? la case à cocher à droite est sélectionnée. Cliquez ensuite sur le bouton Find bouton. (Toute erreur, telle que des problèmes de permission de fichier, sera imprimée au bas de la fenêtre FSlint).

FSlint listera tous les fichiers en double, l'emplacement de leur répertoire et la date du fichier. FSlint vous présente également le nombre d'octets gaspillés à cause des fichiers redondants.

Suppression des doublons

Vous pouvez maintenant sélectionner plusieurs fichiers en utilisant le bouton Shift o Ctrl et le bouton gauche de la souris. Si vous souhaitez sélectionner plusieurs fichiers automatiquement, cliquez sur le bouton Select et vous disposerez d'options telles que la sélection de fichiers en fonction de la date ou la saisie de critères de sélection de type joker.

Si vous devez utiliser la liste des fichiers sélectionnés en dehors de FSlint (peut-être comme entrée de votre propre script), cliquez sur le bouton Save pour enregistrer un fichier texte.

Enfin, vous pouvez supprimer les fichiers sélectionnés en utilisant le bouton Delete ou vous pouvez fusionner les fichiers sélectionnés en utilisant le bouton Merge bouton. Notez que le Merge supprime la fonction non sélectionné de votre système et crée des liens physiques vers les fichiers correspondants. sélectionné des fichiers. Vous utiliserez cette fonction si vous souhaitez conserver votre structure de fichiers existante, mais que vous voulez libérer de l'espace sur votre système.

enter image description here

Fonctionnalités supplémentaires et documentation

FSlint possède d'autres fonctionnalités puissantes qui sont accessibles à partir des onglets du volet de gauche. J'ai trouvé Name clashes est utile lorsque des fichiers portent le même nom, mais sont différents (peut-être parce que vous avez enregistré une version plus récente d'un fichier dans un autre répertoire).

Il existe également un Advanced search parameters en haut de la fenêtre FSlint qui vous permet d'exclure certains répertoires de votre recherche, ou de filtrer vos résultats à l'aide de paramètres.

Ce petit outil simple comporte de nombreuses fonctionnalités puissantes. Il peut vous épargner l'effort de devoir écrire et déboguer un script. Vous pouvez en savoir plus à l'adresse suivante http://www.pixelbeat.org/fslint/ . Voici un lien direct vers le guide en anglais : http://en.flossmanuals.net/fslint/ .

1voto

joeytwiddle Points 1759

Je veux partager cette façon de faire parce que je pense que c'est assez amusant.

Pour chaque sous-dossier situé sous le dossier cible, nous générons un hachage pour ce sous-dossier.

Le hachage de chaque dossier est généré à partir du résultat du hachage de tous les fichiers situés sous ce dossier. Ainsi, tout dossier contenant des fichiers identiques dans la même structure devrait produire le même hachage !

A la fin, nous utilisons uniq pour afficher uniquement les hachages de dossiers en double.

Enregistrez le script suivant en tant que seek_duplicate_folders.sh et ensuite l'exécuter comme ceci :

$ bash seek_duplicate_folders.sh [root_folder_to_scan]

Voici le script :

#!/bin/bash
target="$1"

hash_folder() {
  echo "Hashing $1" >/dev/stderr
  pushd "$1" >/dev/null

  # Hash all the files
  find . -type f | sort | xargs md5sum |

  # Hash that list of hashes, discard the newline character,
  # and append the folder name
  md5sum - | tr -d '\n'
  printf "  %s\n" "$1"

  popd >/dev/null
}

find "$target" -type d |
while read dir
do hash_folder "$dir"
done |
sort |
# Display only the lines with duplicate hashes (first 32 chars are duplicates)
uniq -D -w 32

Mises en garde :

  • Inefficace : il additionne plusieurs fois les fichiers situés en profondeur dans l'arbre (une fois par dossier ancêtre).
  • Ne détecte pas les différences d'horodatage, de propriété ou de permissions des fichiers.
  • Ignore les dossiers vides. Ainsi, deux dossiers qui contiennent des fichiers identiques, ou aucun fichier, mais qui contiennent des dossiers vides différents, seront toujours considérés comme identiques.
  • Ignore les liens symboliques. Les fichiers contenant des liens symboliques différents peuvent néanmoins être considérés comme identiques.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X