web-dev-qa-db-fra.com

Comparez deux fichiers ligne par ligne et générez la différence dans un autre fichier.

Je souhaite comparer fichier1 à fichier2 et générer un fichier3 contenant les lignes de fichier1 qui ne sont pas présentes dans fichier2.

111
Balualways

diff (1) n'est pas la réponse, mais comm (1) l'est.

NAME
       comm - compare two sorted files line by line

SYNOPSIS
       comm [OPTION]... FILE1 FILE2

...

       -1     suppress lines unique to FILE1

       -2     suppress lines unique to FILE2

       -3     suppress lines that appear in both files

Alors

comm -2 -3 file1 file2 > file3

Les fichiers d'entrée doivent être triés. S'ils ne le sont pas, triez-les d'abord. Cela peut être fait avec un fichier temporaire, ou ...

comm -2 -3 <(sort file1) <(sort file2) > file3

à condition que votre shell prenne en charge la substitution de processus (bash le fait).

197
Sorpigal

L'utilitaire Unix diff est conçu pour cela.

$ diff -u file1 file2 > file3

Voir le manuel et Internet pour les options, les différents formats de sortie, etc.

47
Thanatos

Considère ceci:
fichier a.txt:

abcd
efgh

fichier b.txt:

abcd

Vous pouvez trouver la différence avec:

diff -a --suppress-common-lines -y a.txt b.txt

La sortie sera:

efgh 

Vous pouvez rediriger la sortie dans un fichier de sortie (c.txt) en utilisant:

diff -a --suppress-common-lines -y a.txt b.txt > c.txt

Cela répondra à votre question:

"... qui contient les lignes du fichier1 qui ne sont pas présentes dans le fichier2."

20
Neilvert Noval

Parfois diff est l'utilitaire dont vous avez besoin, mais parfois join est plus approprié. Les fichiers doivent être pré-triés ou, si vous utilisez un shell prenant en charge la substitution de processus, tel que bash, ksh ou zsh, vous pouvez effectuer le tri à la volée.

join -v 1 <(sort file1) <(sort file2)
7
Dennis Williamson

Essayer

sdiff file1 file2

Cela fonctionne généralement beaucoup mieux dans la plupart des cas pour moi. Vous souhaiterez peut-être trier les fichiers avant, si l'ordre des lignes n'est pas important (par exemple, certains fichiers de configuration de texte).

Par exemple,

sdiff -w 185 file1.cfg file2.cfg
5
Tagar

Si vous avez besoin de résoudre cela avec coreutils, la réponse acceptée est bonne:

comm -23 <(sort file1) <(sort file2) > file3

Vous pouvez également utiliser sd (stream diff), qui ne nécessite ni tri ni substitution de processus et prend en charge des flux infinis, comme ceci:

cat file1 | sd 'cat file2' > file3

Probablement pas un avantage sur cet exemple, mais considérez-le quand même; dans certains cas, vous ne pourrez pas utiliser comm ni grep -F ni diff.

Voici un blogpost J'ai écrit sur les différents flux sur le terminal, ce qui introduit sd.

3
mlg

Beaucoup de réponses déjà, mais aucune d’elles n’est parfaite à mon humble avis. La réponse de Thanatos laisse quelques caractères supplémentaires par ligne et la réponse de Sorpigal exige que les fichiers soient triés ou pré-triés, ce qui peut ne pas être suffisant dans toutes les circonstances.

Je pense que la meilleure façon d’obtenir les lignes qui sont différentes et rien d’autre (pas de caractères supplémentaires, pas de réorganisation) est une combinaison de diff, grep et awk (ou similaire ).

Si les lignes ne contiennent pas de "<", une ligne courte peut être:

diff urls.txt* | grep "<" | sed 's/< //g'

mais cela supprimera toutes les occurrences de "<" (moins de, espace) des lignes, ce qui n’est pas toujours OK (par exemple, le code source). L'option la plus sûre consiste à utiliser awk:

diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'

Cette une ligne différencie les deux fichiers, puis filtre la sortie de diff du style éd, puis supprime le "<" final ajouté par diff. Cela fonctionne même si les lignes contiennent des "<" eux-mêmes.

2
sergut

Utilisez l'utilitaire Diff et extrayez uniquement les lignes commençant par <dans la sortie

1
Capslockk

Pourtant, pas de solution grep?

  • lignes qui n'existent que dans file2:

    grep -Fxvf file1 file2 > file3
    
  • lignes qui n'existent que dans fichier1:

    grep -Fxvf file2 file1 > file3
    
  • lignes qui existent dans les deux fichiers:

    grep -Fxf file1 file2 > file3
    
1
αғsнιη
diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt

J'ai essayé presque toutes les réponses dans ce fil, mais aucune n'était complète. Après quelques pistes ci-dessus on a travaillé pour moi. diff vous donnera la différence mais avec des caractères spéciaux indésirables. où vos différences réelles commencent par '>'. la prochaine étape consiste donc à grep les lignes commencent par '>' et sont ensuite supprimées par sed.

1
tollin jose

Vous pouvez utiliser diff avec le formatage de sortie suivant:

diff --old-line-format='' --unchanged-line-format='' file1 file2

--old-line-format='', désactive la sortie pour fichier1 si la ligne est différente, comparez-la dans fichier2.
--unchanged-line-format='', désactive la sortie si les lignes sont identiques.

0
αғsнιη

Je suis surpris que personne n'ait mentionné diff -y à produire une sortie côte à côte, par exemple:

diff -y file1 file2 > file3

Et dans file3 (les différentes lignes ont un symbole | au milieu):

same     same
diff_1 | diff_2
0
xtluo