Vergelijk twee bestanden regel voor regel en genereer het verschil in een ander bestand

Ik wil bestand1 vergelijken met bestand2 en een bestand3 genereren dat de regels in bestand1 bevat die niet aanwezig zijn in bestand2.


Antwoord 1, autoriteit 100%

diff(1) is niet het antwoord, maar comm(1) wel.

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

Dus

comm -2 -3 file1 file2 > file3

De invoerbestanden moeten worden gesorteerd. Als dat niet het geval is, sorteert u ze eerst. Dit kan met een tijdelijk bestand, of…

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

op voorwaarde dat uw shell procesvervanging ondersteunt (bash doet dat).


Antwoord 2, autoriteit 20%

Het Unix-hulpprogramma diffis precies voor dit doel bedoeld.

$ diff -u file1 file2 > file3

Zie de handleiding en internet voor opties, verschillende uitvoerformaten, enz.


Antwoord 3, autoriteit 9%

Overweeg dit:
bestand a.txt:

abcd
efgh

bestand b.txt:

abcd

Je kunt het verschil vinden met:

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

De uitvoer zal zijn:

efgh 

U kunt de uitvoer in een uitvoerbestand (c.txt) omleiden met:

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

Dit zal je vraag beantwoorden:

“…die de regels in file1 bevat die
niet aanwezig in bestand2.”


Antwoord 4, autoriteit 5%

Soms is diffhet hulpprogramma dat je nodig hebt, maar soms is joinmeer geschikt. De bestanden moeten vooraf worden gesorteerd of, als u een shell gebruikt die procesvervanging ondersteunt, zoals bash, ksh of zsh, kunt u de sortering direct uitvoeren.

join -v 1 <(sort file1) <(sort file2)

Antwoord 5, autoriteit 4%

Toch geen grepoplossing?

  • regels die alleen in file2 bestaan:

    grep -Fxvf file1 file2 > file3
    
  • regels die alleen in file1 voorkomen:

    grep -Fxvf file2 file1 > file3
    
  • regels die in beide bestanden voorkomen:

    grep -Fxf file1 file2 > file3
    

Antwoord 6, autoriteit 2%

Probeer

sdiff file1 file2

Het werkt bij mij meestal veel beter.
Misschien wilt u bestanden eerst sorteren als de volgorde van de regels niet belangrijk is (bijv. sommige tekstconfiguratiebestanden).

Bijvoorbeeld

sdiff -w 185 file1.cfg file2.cfg

Antwoord 7

Als je dit met coreutils moet oplossen, is het geaccepteerde antwoord goed:

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

Je kunt ook sd(stream diff) gebruiken, waarvoor geen sortering of procesvervanging nodig is en ondersteunt oneindige streams, zoals:

cat file1 | sd 'cat file2' > file3

Waarschijnlijk niet zo’n groot voordeel voor dit voorbeeld, maar overweeg het toch; in sommige gevallen kunt u commnoch grep -Fnoch diffgebruiken.

Hier is een blogpostIk schreef over verschillende streams op de terminal, die sd introduceert.


Antwoord 8

Veel antwoorden al, maar geen van hen is perfect IMHO. Het antwoord van Thanatos laat wat extra tekens per regel achter en het antwoord van Sorpigal vereist dat de bestanden worden gesorteerd of voorgesorteerd, wat mogelijk niet onder alle omstandigheden voldoende is.

Ik denk dat de beste manier om de regels te krijgen die anders zijn en niets anders (geen extra tekens, geen nieuwe volgorde) een combinatie is van diff, grep, en awk(of vergelijkbaar).

Als de regels geen “<” bevatten, kan een korte oneliner zijn:

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

maar dat zal elke instantie van “<” (minder dan, spatie) uit de regels verwijderen, wat niet altijd in orde is (bijv. broncode). De veiligste optie is om awk te gebruiken:

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

Deze one-liner differentieert beide bestanden, filtert vervolgens de ed-stijl uitvoer van diff eruit en verwijdert vervolgens de achterliggende “<” dat diff voegt toe. Dit werkt zelfs als de regels wat “<” bevatten zich.


Antwoord 9

U zou diffkunnen gebruiken met de volgende uitvoeropmaak:

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

--old-line-format='', schakel uitvoer voor bestand1 uit als regel anders was, vergelijk in bestand2.
--unchanged-line-format='', schakel uitvoer uit als de regels hetzelfde waren.


Antwoord 10

Het verbaast me dat niemand diff -ynoemde om een zij-aan-zij-uitvoer te produceren, bijvoorbeeld:

diff -y file1 file2 > file3

En in file3(verschillende regels hebben een symbool |in het midden):

same     same
diff_1 | diff_2

Antwoord 11

Gebruik het hulpprogramma Diff en extraheer alleen de regels die beginnen met < in de uitvoer


Antwoord 12

diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt

Ik heb bijna alle antwoorden in deze thread geprobeerd, maar geen enkele was compleet. Na een paar paden boven werkte er een voor mij. diffgeeft je verschil, maar met enkele ongewenste speciale tekens. waar uw werkelijke verschilregels beginnen met ‘> ‘. dus de volgende stap is om grepregels te laten beginnen met ‘> ‘en gevolgd door hetzelfde te verwijderen met sed.


Antwoord 13

Als je een CSV-bestand hebt met enkele of zelfs meerdere kolommen, kun je deze regel voor regel “diff”-bewerkingen uitvoeren met de sqlite3 embedded db. Het wordt geleverd met python, dus zou beschikbaar moeten zijn op de meeste linux/macs. Je kunt de sqlite3-opdrachten op de bash-shell scripten zonder dat je python hoeft te schrijven.

  1. Maak uw a.csv- en b.csv-bestanden
  2. Zorg ervoor dat sqlite3 is geïnstalleerd met het commando “sqlite3 -help”
  3. Voer de onderstaande opdrachten rechtstreeks uit op de Linux/Mac-shell (of plaats het in een script)

echo "
.mode csv
.import a.csv atable
.import b.csv btable
create table result as select * from atable EXCEPT select * from btable;
.output result.csv
select * from result ;
.quit
" | sqlite3 temp.db

Opmerking: zorg ervoor dat er een nieuwe regelis voor elk van de sqlite3-opdrachten.

Hoe het werkt

  1. Importeer de 2 csv’s in respectievelijk “atable” en “btable”.
  2. Gebruik de sql-operator “behalve” om de gegevens te selecteren die beschikbaar zijn in “atable” maar ontbreken in “btable”. Maak een “resultaten”-tabel met behulp van de select query-instructie
  3. Voer de resultatentabel uit naar result.csv door “select * from result;” uit te voeren

Als u op specifieke kolommen moet werken, is sqlite3 of eender welke db de juiste keuze.

Ik heb geprobeerd om op meerdere GB-bestanden te differentiëren met behulp van de ingebouwde diff- en comm-tools. Sqlite verslaat linux-hulpprogramma’s met een mijl.

Other episodes