web-dev-qa-db-fra.com

Comment puis-je faire en sorte que diff affiche uniquement les lignes ajoutées et supprimées? Si diff ne peut pas le faire, quel outil peut-il faire?

Comment puis-je faire en sorte que diff affiche uniquement les lignes ajoutées et supprimées? Si diff ne peut pas le faire, quel outil peut-il faire?

71
C. Ross

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 dans l'autre: (mais pas les deux)

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

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

Fichiers triés uniquement

REMARQUE: Les deux fichiers doivent être triés pour que comm fonctionne 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 être assez lourd car cela nécessite une copie supplémentaire et donc deux fois plus d'espace disque.

85
TomOnTime

comm pourrait faire ce que vous voulez. Depuis sa page de manuel:

LA DESCRIPTION

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

Sans aucune option, produisez une sortie à trois colonnes. La première colonne contient des lignes propres à 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, -2 et -3 respectivement.

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 triés au préalable.

15
markdrayton

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

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

Par exemple, compte tenu 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 

production:

B-ONLY
A-ONLY

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

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

production:

A-ONLY

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

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

production

B-ONLY
10
iphonedroid

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

diff -b -B

doit ignorer les lignes vides et les différents nombres d'espaces.

2
Scott Lundberg

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

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

Les outils de comparaison visuelle assemblent deux fichiers afin qu'un segment avec le même nombre de lignes mais un contenu différent soit considéré comme un segment modifié. De 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 montre une comparaison côte à côte de deux fichiers dans 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 caractère de séparation. 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 l'utiliser pour afficher uniquement les lignes ajoutées:

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

Merci senarvi, votre solution (non votée) m'a en fait donné exactement ce que je voulais après avoir recherché les âges 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 appropriés.

#!/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}'
2
geniosity

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

Production:

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

Il montre donc les anciennes lignes avec - suivi immédiatement de la nouvelle ligne correspondante avec +.

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

cela ressemble à ceci:

-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 connexe: https://stackoverflow.com/questions/15384818/how-to-get-the-difference-only-additions-between-two-files-in-linux

Testé dans Ubuntu 18.04.