J'ai deux fichiers de configuration, l'original du gestionnaire de paquets et un fichier personnalisé modifié par moi-même. J'ai ajouté quelques commentaires pour décrire le comportement.
Comment puis-je exécuter diff
sur les fichiers de configuration, en ignorant les commentaires? Une ligne commentée est définie par:
#
)L'expression régulière (la plus simple) ignorant la première condition serait #.*
. J'ai essayé le --ignore-matching-lines=RE
(-I RE
) option de GNU diff 3.0, mais je n'ai pas pu le faire fonctionner avec cette RE. J'ai également essayé .*#.*
et .*\#.*
sans chance. Mettre littéralement la ligne (Port 631
) car RE
ne correspond à rien, et n'aide pas non plus à mettre le RE entre les barres obliques.
Comme suggéré dans la saveur regex de l'outil "diff" semble manquer? , j'ai essayé grep -G
:
grep -G '#.*' file
Cela semble correspondre aux commentaires, mais cela ne fonctionne pas pour diff -I '#.*' file1 file2
.
Alors, comment utiliser cette option? Comment puis-je faire diff
sauter certaines lignes (dans mon cas, les commentaires)? Veuillez ne pas suggérer grep
ing le fichier et comparer les fichiers temporaires.
Selon Gilles, l'option -I
N'ignore une ligne que si rien d'autre à l'intérieur de cet ensemble ne correspond à l'exception de la correspondance de -I
. Je ne l'ai pas complètement compris avant de l'avoir testé.
Trois fichiers sont impliqués dans mon test:
Fichier test1
:
text
Fichier test2
:
text
#comment
Fichier test3
:
changed text
#comment
Les commandes:
$ # comparing files with comment-only changes
$ diff -u -I '#.*' test{1,2}
$ # comparing files with both comment and regular changes
$ diff -u -I '#.*' test{2,3}
--- test2 2011-07-20 16:38:59.717701430 +0200
+++ test3 2011-07-20 16:39:10.187701435 +0200
@@ -1,2 +1,2 @@
-text
+changed text
#comment
Puisqu'il n'y a pas de réponse pour l'instant expliquant comment utiliser correctement l'option -I
, Je vais fournir une alternative qui fonctionne dans les shells bash:
diff -u -B <(grep -vE '^\s*(#|$)' test1) <(grep -vE '^\s*(#|$)' test2)
diff -u
- diff unifié -B
- ignorer les lignes vides<(command)
- une fonction bash appelée substitution de processus qui ouvre un descripteur de fichier pour la commande, cela supprime le besoin d'un fichier temporairegrep
- commande pour imprimer des lignes correspondant (non) à un motif -v
- affiche les lignes qui ne correspondent pasE
- utilise des expressions régulières étendues'^\s*(#|$)'
- une expression régulière correspondant aux commentaires et aux lignes vides ^
- correspond au début d'une ligne\s*
- correspond aux espaces (tabulations et espaces) le cas échéant(#|$)
Correspond à une marque de hachage ou à la fin d'une ligneEssayer:
diff -b -I '^#' -I '^ #' file1 file2
Veuillez noter que l'expression régulière doit correspondre à la ligne correspondante dans les deux fichiers et qu'elle correspond à chaque ligne modifiée dans le morceau pour fonctionner, sinon elle affichera toujours la différence.
Utilisez des guillemets simples pour protéger le modèle contre l'expansion de Shell et pour échapper aux caractères réservés aux expressions régulières (par exemple, les crochets).
Nous pouvons lire dans le manuel diffutils
:
Cependant,
-I
ignore uniquement l'insertion ou la suppression de lignes qui contiennent l'expression régulière si chaque ligne modifiée dans le morceau (chaque insertion et chaque suppression) correspond à l'expression régulière.En d'autres termes, pour chaque changement non ignorable,
diff
imprime l'ensemble complet des changements à son voisinage, y compris les ignorables. Vous pouvez spécifier plusieurs expressions régulières pour les lignes à ignorer en utilisant plusieurs-I
option.diff
essaie de faire correspondre chaque ligne à chaque expression régulière, en commençant par la dernière donnée.
Ce comportement est également bien expliqué par armel ici .
Connexes: Comment puis-je effectuer un diff qui ignore tous les commentaires?
Après une recherche sur le Web, le meilleur moyen de Lekensteyn est le meilleur que j'ai trouvé.
Mais je veux utiliser la sortie dif comme patch ... et il y a un problème car les numéros de ligne sont conservés à cause de "grep -v".
J'ai donc l'intention d'améliorer cette ligne de commande:
diff -u -B <(sed 's/^[[:blank:]]*#.*$/ /' file1) <(sed 's/^[[:blank:]]*#.*$/ /' file2)
Ce n'est pas parfait, mais le numéro de ligne est conservé dans le fichier patch.
Cependant, si une nouvelle ligne est ajoutée à la place de la ligne de commentaire ... le commentaire produira un Hunk FAILED lors du patch comme nous pouvons le voir ci-dessous.
File test1:
text
#comment
other text
File test2:
text
new line here
#comment changed
other text changed
tester maintenant notre commande
$ echo -e "#!/usr/bin/sed -f\ns/^[[:blank:]]*#.*$/ /" > outcom.sed
$ echo "diff -u -B <(./outcom.sed \$1) <(./outcom.sed \$2)" > mydiff.sh
$ chmod +x mydiff.sh outcom.sed
$ ./mydiff.sh file1 file2 > file.dif
$ cat file.dif
--- /dev/fd/63 2014-08-23 10:05:08.000000000 +0200
+++ /dev/fd/62 2014-08-23 10:05:08.000000000 +0200
@@ -1,2 +1,3 @@
text
+new line
-other text
+other text changed
/ dev/fd/62 &/dev/fd/63 sont des fichiers produits par substitution de processus. La ligne entre "+ nouvelle ligne" et "-autre texte" est le caractère d'espace par défaut défini dans notre expression sed pour remplacer les commentaires.
Et maintenant, qu'est-ce qui arrive lorsque nous appliquons ce patch:
$ patch -p0 file1 < file.dif
patching file file1
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file file1.rej
La solution consiste à ne pas utiliser le format diff unifié sans -u
$ echo "diff -B <(./outcom.sed \$1) <(./outcom.sed \$2)" > mydiff.sh
$ ./mydiff.sh file1 file2 > file.dif
$ cat file.dif
1a2
> new line
3c4
< other text
---
> other text changed
$ patch -p0 file1 < file.dif
patching file file1
$ cat file1
text
new line
#comment
other text changed
maintenant fichier de travail fichier de patch (sans garantie de résultat dans un processus de diff très complexe).
J'ignore généralement cet encombrement par:
grep -v "^#" | cat -s
et en les différenciant ou ...vim -d
pour consulter les fichiers. La mise en évidence de la syntaxe prend soin de rendre les différences entre commentaires et non-commentaires assez évidentes. La mise en évidence diff de la différence en ligne afin que vous puissiez voir quelles valeurs ou parties de valeurs ont été modifiées en un coup d'œil en fait mon préféré.Voici ce que j'utilise pour supprimer toutes les lignes commentées - même celles commençant par un onglet ou un espace - et les vides:
egrep -v "^$|^[[:space:]]*#" /path/to/file
ou vous pouvez faire
sed -e '/^#.*/d' -e 's/#.*//g' | cat -s