web-dev-qa-db-fra.com

Comparer récursivement deux répertoires avec diff -r sans sortie sur des liens rompus

J'utilise diff -r a b pour comparer récursivement les répertoires a et b. Il arrive souvent cependant qu'il y ait des liens cassés (les mêmes liens cassés dans les deux répertoires a et b et pointant vers les mêmes cibles inexistantes).

diff affiche ensuite des messages d'erreur pour ces cas et quitte avec un code de sortie non nul, mais je voudrais qu'il reste silencieux et quitte avec 0 car les répertoires sont les mêmes dans mon livre.

Comment puis je faire ça?

44

Pour la version 3.3 ou ultérieure de diff, vous devez utiliser le --no-dereference option, comme décrit dans réponse de Pete Harlan .

Malheureusement, les anciennes versions de diffne prennent pas en charge l'ignorance des liens symboliques :

Certains fichiers ne sont ni des répertoires ni des fichiers normaux: ce sont des fichiers inhabituels comme des liens symboliques, des fichiers spéciaux de périphérique, des canaux nommés et des sockets. Actuellement, diff traite les liens symboliques comme des fichiers normaux; il traite d'autres fichiers spéciaux comme des fichiers normaux s'ils sont spécifiés au niveau supérieur, mais signale simplement leur présence lors de la comparaison de répertoires. Cela signifie que patch ne peut pas représenter les modifications apportées à ces fichiers. Par exemple, si vous modifiez le fichier vers lequel pointe un lien symbolique, diff affiche la différence entre les deux fichiers, au lieu de la modification du lien symbolique.

diff doit facultativement signaler les modifications apportées aux fichiers spéciaux, et patch doit être étendu pour comprendre ces extensions.

Si tout ce que vous voulez est de vérifier un rsync (et probablement de corriger ce qui manque), vous pouvez simplement exécuter la commande rsync une deuxième fois. Si vous ne voulez pas faire cela, alors vérifier la somme du répertoire peut être suffisant.

Si vous voulez vraiment le faire avec diff, vous pouvez utiliser find pour ignorer les liens symboliques et exécuter diff sur chaque fichier individuellement. Passez vos répertoires a et b comme arguments:

#!/bin/bash
# Skip files in $1 which are symlinks
for f in `find $1/* ! -type l`
do
    # Suppress details of differences
    diff -rq $f $2/${f##*/}
done

ou en une ligne:

for f in `find a/* ! -type l`;do diff -rq $f b/${f##*/};done

Cela identifiera les fichiers dont le contenu diffère, ou les fichiers qui sont dans a mais pas dans b.

Notez que:

  • puisque nous ignorons complètement les liens symboliques, cela ne remarquera pas si les noms de liens symboliques ne sont pas présents dans b. Si vous en aviez besoin, vous auriez besoin d'une seconde passe de recherche pour identifier tous les liens symboliques, puis vérifier explicitement leur existence dans b.
  • Les fichiers supplémentaires dans b ne seront pas identifiés, car la liste est construite à partir du contenu de a. Ce n'est probablement pas un problème pour votre scénario rsync.
29
ire_and_curses

Depuis la version 3.3 GNU diff ne prend pas en charge le déréférencement des liens symboliques, mais compare ensuite les chemins vers lesquels ils pointent.

Installez GNU diffutils> = 3.3 et utilisez le --no-dereference option; il n'y a pas d'option courte pour cela.

Le diagnostic sera silencieux s'il est égal ou:

Liens symboliques /tmp/noderef/a/symlink et /tmp/noderef/b/symlink différer

21

Vous pouvez utiliser une version plus récente de diff

diff in GNU diffutils 3.3 inclut un --no-dereference option qui vous permet de comparer les liens symboliques eux-mêmes plutôt que leurs cibles. Il signale s'ils diffèrent, est silencieux s'ils sont d'accord et ne se soucie pas s'ils sont cassés.

Je ne sais pas quand l'option a été ajoutée; il n'est pas présent en 2.8.1.

6
Pete Harlan