Comment puis-je obtenir diff pour montrer uniquement les lignes ajoutées et supprimées? Si diff ne peut pas le faire, quel outil le peut?

69

Comment puis-je obtenir diff pour montrer uniquement les lignes ajoutées et supprimées? Si diff ne peut pas le faire, quel outil le peut?

Traverser
la source
2
Vous devez mieux définir ce que vous entendez par ajouté et supprimé. Plus précisément, une ligne peut-elle changer? Si oui, comment voulez-vous que la ligne modifiée soit traitée? Si vous effectuez une vérification strictement orientée ligne, une modification de ligne est identique à l'ancienne ligne supprimée et à la nouvelle ligne ajoutée. Par exemple, comment devrait-il gérer une ligne divisée en deux? Comme deux 1 ligne a changé? 2 lignes changées? 1 ligne supprimée et 2 lignes ajoutées? À moins que vous ne puissiez garantir que les lignes ne changeront jamais, qu'elles soient simplement ajoutées et supprimées, je pense que cela est voué à l'échec sans meilleures définitions.
Christopher Cashell
Je trouve la question assez peu claire. Mais au moins une interprétation de la question pourrait être répondue avecdiff A B | grep '^[<>]'
kasperd
Vous recherchez peut-être comm.
Jenny D dit: réintégrer Monica le
@ChristopherCashell, il signifie ignorer l'ordre de tri; un problème typique commun. Cela se fait généralement en triant d'abord les segments (lignes) de chaque côté avant de faire un diff typique.
Pacerier
@Pacerier, tu es sûr de ça? Ou devinez vous? Rien sur le tri ou l'ordre de recherche n'est mentionné ou fait allusion dans la question. Dans l'état actuel des choses, la question n'est pas claire et pourrait être interprétée de différentes manières. Sans savoir avec certitude ce qu'il demande, nous formulons des hypothèses et proposons des solutions qui peuvent ou non résoudre le problème. De plus, le commentaire de l’affiche originale sur l’une des réponses suggère que cela n’est pas lié au tri. Cela a à voir avec la signification de "ajouté et supprimé" vs "changé".
Christopher Cashell

Réponses:

82

Essayez comm

Une autre façon de voir les choses:

  • Afficher les lignes qui n'existent que dans le fichier a: (c'est-à-dire ce qui a été supprimé de a)

    comm -23 a b
    
  • Afficher les lignes qui n'existent que dans le fichier b: (c'est-à-dire ce qui a été ajouté à b)

    comm -13 a b
    
  • Afficher les lignes qui n'existent que dans un fichier ou l'autre: (mais pas les deux)

    comm -3 a b | sed 's/^\t//'
    

(Avertissement: si le fichier acontient des lignes commençant par TAB, il (le premier TAB) sera supprimé de la sortie.)

Fichiers triés seulement

REMARQUE: Les deux fichiers doivent être triés pour commfonctionner correctement. S'ils ne sont pas déjà triés, vous devez les trier:

sort <a >a.sorted
sort <b >b.sorted
comm -12 a.sorted b.sorted

Si les fichiers sont extrêmement longs, cela peut s'avérer fastidieux, car il nécessite une copie supplémentaire et par conséquent deux fois plus d'espace disque.

TomOnTime
la source
5
je voulais juste ajouter que les deux fichiers doivent être triés (sensible à la casse) pour que cette solution produise des résultats corrects
marmor
1
Sur des coquilles assez modernes, vous pouvez trier en ligne avec quelque chose commecomm -12 <(sort a) <(sort b)
Joshua Huber
14

commpourrait faire ce que vous voulez. De sa page de manuel:

LA DESCRIPTION

Comparez les fichiers triés FILE1 et FILE2 ligne par ligne.

En l'absence d'options, créez une sortie sur trois colonnes. La première colonne contient des lignes uniques à FILE1, la deuxième colonne contient des lignes uniques à FILE2 et la troisième colonne contient des lignes communes aux deux fichiers.

Ces colonnes sont supprimables avec -1, -2et -3respectivement.

Exemple:

[root@dev ~]# cat a
common
shared
unique

[root@dev ~]# cat b
common
individual
shared

[root@dev ~]# comm -3 a b
    individual
unique

Et si vous voulez juste les lignes uniques et ne vous souciez pas du fichier dans lequel elles se trouvent:

[root@dev ~]# comm -3 a b | sed 's/^\t//'
individual
unique

Comme le dit la page de manuel, les fichiers doivent être préalablement triés.

Markdrayton
la source
9

Pour afficher les ajouts et les suppressions sans contexte, numéros de ligne, +, -, <,>! etc, vous pouvez utiliser diff comme ceci:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

Par exemple, à partir de deux fichiers:

a.txt

Common
Common
A-ONLY
Common

b.txt

Common
B-ONLY
Common
Common

La commande suivante affichera les lignes supprimées de a ou ajoutées à b:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

sortie:

B-ONLY
A-ONLY

Cette commande légèrement différente montrera les lignes supprimées de a.txt:

diff --changed-group-format='%<' --unchanged-group-format='' a.txt b.txt 

sortie:

A-ONLY

Enfin, cette commande affichera les lignes ajoutées à a.txt

diff --changed-group-format='%>' --unchanged-group-format='' a.txt b.txt 

sortie

B-ONLY
iphonedroid
la source
2

C'est ce que diff fait par défaut ... Peut-être avez-vous besoin d'ajouter des drapeaux pour ignorer les espaces?

diff -b -B

devrait ignorer les lignes vides et un nombre différent d'espaces.

Scott Lundberg
la source
1
Non, il affiche également les lignes MODIFIÉES (les lignes ayant un caractère ou quatre caractères différents). Je veux des lignes qui n'existent qu'à gauche ou à droite.
C. Ross
2
Vous pourriez faire valoir que les différentes versions d'un fichier CHANGED n'existent que dans les versions gauche ou droite.
Markdrayton
2
Diff (ou tout autre outil) n'a aucun moyen de dire de manière fiable ce qui constitue un changement et ce qui remplace une ligne supprimée par une nouvelle ligne.
Cian
1
Techniquement, diff traite une ligne "modifiée" comme si la ligne d'origine avait été supprimée et qu'une nouvelle ligne avait été ajoutée ... donc techniquement, elle ne montre que les lignes ajoutées et supprimées.
KFro
2

Non, diffne montre pas réellement les différences entre deux fichiers dans la façon dont on pourrait penser. Il produit une séquence de commandes d'édition pour un outil, patchà utiliser pour changer un fichier dans un autre.

La difficulté pour toute tentative de faire ce que vous cherchez est de savoir comment définir ce qui constitue une ligne modifiée par rapport à une ligne supprimée suivie d’une ligne ajoutée. De plus, que faire lorsque des lignes sont ajoutées, supprimées et modifiées les unes à côté des autres.

Dennis Williamson
la source
Mes pensées exactement. Quel pourcentage de caractères dans une ligne doit être modifié pour être considéré comme un nouveau plutôt que comme une modification de l'original? Techniquement, même si vous avez un caractère en commun, vous pouvez considérer cela comme un "changement" au lieu d'une suppression et d'une insertion.
Kamil Kisiel
1
Cela fait longtemps que je n’ai pas regardé les diffsources, mais je me souviens de toutes sortes de gyrations pour garder la trace de la concordance de deux fichiers afin de rester synchronisés et je pense qu’il ya un seuil pour abandonner basé sur la distance qui sépare les fichiers. les lignes sont. Mais je ne me souviens d'aucune correspondance intra-ligne, sauf en ce qui concerne l'espace blanc réduit ou le cas ignoré. Ou (peut-être) des mots à cet effet. Dans tous les cas, il s’agit de patch"vgrep". Peut être. Mardi.
Dennis Williamson
2

Les outils de comparaison visuelle associent deux fichiers pour qu'un segment comportant le même nombre de lignes mais dont le contenu diffère soit considéré comme un segment modifié. Les nouvelles lignes entre les segments correspondants sont considérées comme des segments ajoutés.

C’est également ainsi que fonctionne l’ outil de ligne de commande sdiff , qui présente une comparaison côte à côte de deux fichiers d’un terminal. Les lignes modifiées sont séparées par | personnage. Si une ligne n'existe que dans le fichier A, <est utilisé comme séparateur. Si une ligne n'existe que dans le fichier B,> est utilisé comme séparateur. Si vous n'avez pas de caractères <et> dans les fichiers, vous pouvez utiliser ceci pour afficher uniquement les lignes ajoutées:

sdiff A B | grep '[<>]'
Seppo Enarvi
la source
2

Merci senarvi, votre solution (non votée pour) m'a en fait EXACTEMENT ce que je voulais après avoir cherché des siècles sur une tonne de pages.

En utilisant votre réponse, voici ce que j’ai trouvé pour obtenir la liste des choses modifiées / ajoutées / supprimées. L'exemple utilise 2 versions du fichier / etc / passwd et imprime le nom d'utilisateur pour les enregistrements pertinents.

#!/bin/bash
sdiff passwd1 passwd2 | grep '[|]' | awk -F: '{print "changed: " $1}'
sdiff passwd1 passwd2 | grep '[<]' | awk -F: '{print "deleted: " $1}'
sdiff passwd1 passwd2 | grep '[>]' | awk -F\> '{print $2}' | awk -F: '{print "added: " $1}'
géniosité
la source
Notez que parce que la différence entre "une ligne a été modifiée" et "une ligne a été supprimée et une autre ligne a été ajoutée en dessous ou au dessus" est sémantique. Un outil de différenciation générique basé sur le texte ne peut pas séparer ces cas. Par conséquent, votre réponse basée sur sdiff ne peut pas fonctionner de manière fiable dans tous les cas.
Mikko Rantalainen
0

Je trouve cette forme particulière souvent utile:

diff --changed-group-format='-%<+%>' --unchanged-group-format='' f g

Exemple:

printf 'a\nb\nc\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

Sortie:

-b
-c
+B
+C
-e
-f
+E
+F

Ainsi, il affiche les anciennes lignes -suivies immédiatement de la nouvelle ligne correspondante +.

Si nous avions une suppression de C:

printf 'a\nb\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

ça ressemble à ça:

-b
+B
+C
-e
-f
+E
+F

Le format est documenté à man diff:

       --line-format=LFMT
              format all input lines with LFMT`

et:

       LTYPE is 'old', 'new', or 'unchanged'.
              GTYPE is LTYPE or 'changed'.

et:

              LFMT (only) may contain:

       %L     contents of line

       %l     contents of line, excluding any trailing newline

       [...]

Question associée: https://stackoverflow.com/questions/15384818/how-to-get-the-difference-only-additions-between-two-files-in-linux

Testé dans Ubuntu 18.04.

Ciro Santilli 改造 中心 六四 事件
la source
-1

Fichier1:

text670_1
text067_1
text067_2

Fichier2:

text04_1
text04_2
text05_1
text05_2
text067_1
text067_2
text1000_1

Utilisation:

diff -y file1 file2

Cette affiche deux colonnes pour les fichiers repectives.

Sortie:

text670_1                           
                                  > text04_1
                                  > text04_2
                                  > text05_1
                                  > text05_2
text067_1                           text67_1
text067_2                           text67_2
                                  > text1000_1
Adriano
la source