Comparer deux dossiers en ligne de commande
Parfois, nous pouvons avoir besoin de comparer le contenu de deux dossiers et éventuellement de leurs sous-dossiers, sans comparer leur contenu, mais uniquement leur nom.
Si vous souhaitez comparer le contenu des fichiers, vous pouvez consulter l’article de Jérémy Buget qui traite le sujet.
1er cas : comparer deux dossiers sans sous-dossiers
Pour ce faire, j’en suis arrivé à la commande suivante :
diff <(ls dir1) <(ls dir2)
Ou encore pour avoir un autre affichage du diff :
diff --unified <(ls dir1) <(ls dir2)
Dans cette commande, nous pouvons y trouver <()
.
Il s’agit
du Process Substitution
qui permet d’éviter de stocker le résultat d’une commande dans un fichier temporaire pour s’en servir ensuite.
Cela réduit considérablement le nombre de commandes, nous nous retrouvons avec les commandes du dessus au lieu de :
ls dir1 > tmp_dir1.txt
ls dir2 > tmp_dir2.txt
diff tmp_dir1.txt tmp_dir2.txt
rm tmp_dir1.txt tmp_dir2.txt
Revenons à nos premières commandes en analysant le résultat de celles-ci.
Pour les exemples suivants, j’ai créé deux dossiers :
❯ tree
.
├── dir1
│ ├── bar.html
│ ├── foo.html
│ ├── index.html
│ └── waldo
│ └── garply.html
└── dir2
├── corge.html
├── foo.html
└── index.html
4 directories, 7 files
Nous pouvons donc voir que foo.html
et index.html
sont présents dans les deux dossiers, bar.html
et waldo/garply.html
uniquement dans le premier.
En lançant ces commandes, nous obtenons ce résultat :
❯ diff <(ls dir1) <(ls dir2)
1c1
< bar.html
---
> corge.html
4d3
< waldo
Cette commande renvoie uniquement les différences entre les deux dossiers.
❯ diff --unified <(ls dir1) <(ls dir2)
--- /dev/fd/11 2023-03-06 18:33:47
+++ /dev/fd/12 2023-03-06 18:33:47
@@ -1,4 +1,3 @@
-bar.html
+corge.html
foo.html
index.html
-waldo
Celle-ci, nous montre un diff façon git.
Ces commandes peuvent être suffisantes, mais nous pouvons aller plus loin et répondre à plus de cas d’usage avec la
commande comm
.
Elle nous permet par exemple de voir uniquement les fichiers présents et/ou manquants dans un des dossiers.
Voyons voir le résultat de cette commande sans option :
❯ comm <(ls dir1) <(ls dir2)
bar.html
corge.html
foo.html
index.html
waldo
Nous pouvons distinguer 3 colonnes séparées par des tabulations :
- La première correspond au fichier présent que dans le premier dossier
- La deuxième, uniquement dans le second
- La troisième, les fichiers en commun
Nous nous retrouvons à mon sens avec un diff plus explicite.
Attention, il faut que les fichiers passés en paramètres soient triés par ordre alphabétique pour que la commande fonctionne correctement.
Maintenant que nous avons vu l’usage basique, nous pouvons utiliser les options.
Nous pouvons afficher des colonnes spécifiques grâce à l’option -
suivi
des numéros de colonne à ne pas afficher.
Exemple :
- Afficher uniquement les fichiers en commun :
❯ comm -12 <(ls dir1) <(ls dir2)
foo.html
index.html
- Afficher uniquement les fichiers manquants dans le deuxième dossier :
❯ comm -23 <(ls dir1) <(ls dir2)
bar.html
waldo
2ème cas : comparer deux dossiers avec des sous-dossiers
Pour ce cas, nous allons utiliser la commande diff
avec l’option -r
qui permet de comparer récursivement les
dossiers :
❯ diff -r dir1 dir2
Only in dir1: bar.html
Only in dir2: corge.html
Only in dir1: waldo
Cette commande nous permet de voir les différences entre les deux dossiers, mais nous ne pouvons pas voir les fichiers des sous-dossiers manquants.
Pour cela, nous allons utiliser la commande find
qui, en plus de pouvoir chercher un fichier, permet de lister les
fichiers d’un dossier et de ses sous-dossiers.
Utilisée seule, elle donne :
❯ find dir1
dir1
dir1/index.html
dir1/bar.html
dir1/foo.html
dir1/waldo
dir1/waldo/garply.html
Comme nous pouvons le voir, elle nous donne le chemin complet des fichiers, ce qui n’est pas très pratique pour la
suite. Nous utiliserons en plus la commande sed
qui permet de remplacer une chaîne de caractères pour ne pas avoir le
nom du dossier dans lequel nous cherchons.
❯ find dir1 | sed 's/dir1//g'
/index.html
/bar.html
/foo.html
/waldo
/waldo/garply.html
Nous obtenons donc le résultat que nous voulons pour pouvoir utiliser la commande comm
.
❯ comm <(find dir1 | sed 's/dir1//g' | sort) <(find dir2 | sed 's/dir2//g' | sort)
/bar.html
/corge.html
/foo.html
/index.html
/waldo
/waldo/garply.html
Conclusion
Nous avons vu comment comparer deux dossiers en ligne de commande, avec ou sans sous-dossiers. L’usage de comm nous permet, je trouve, d’avoir un affichage plus explicite que celui de diff et de répondre à plus de cas d’usage.
Si vous souhaitez voir un cas d’usage de ces commandes vous pouvez consulter cette Pull Request où cela m’a été utile.