Vraag Hoe kan ik diff krijgen om alleen toegevoegde en verwijderde regels weer te geven? Als diff het niet kan, wat voor gereedschap kan dat dan?


Hoe kan ik diff krijgen om alleen toegevoegde en verwijderde regels weer te geven? Als diff het niet kan, wat voor gereedschap kan dat dan?


60
2017-09-25 12:47


oorsprong


U moet beter definiëren wat u bedoelt met toegevoegd en verwijderd. Kan een regel in het bijzonder veranderen? Zo ja, hoe wilt u dat een gewijzigde regel wordt afgehandeld? Als u strikt lijngeoriënteerd controleert, is een lijnwisseling identiek aan de oude regel die wordt verwijderd en de nieuwe regel die wordt toegevoegd. Hoe moet bijvoorbeeld een regel worden behandeld die in tweeën is gesplitst? Als twee 1 lijn veranderd? 2 regels veranderd? 1 regel verwijderd en 2 regels toegevoegd? Tenzij u kunt garanderen dat regels nooit zullen veranderen, gewoon worden toegevoegd en verwijderd, ik denk dat dit gedoemd is te mislukken zonder betere definities. - Christopher Cashell
Ik vind de vraag vrij onduidelijk. Maar er kon ten minste één interpretatie van de vraag worden beantwoord diff A B | grep '^[<>]' - kasperd
Misschien ben je op zoek naar comm. - Jenny D
@ChristopherCashell, hij bedoelt de sorteervolgorde negeren; een typisch veelvoorkomend probleem. Meestal gebeurt dit door eerst de segmenten (lijnen) aan elke kant te sorteren voordat een typische diff wordt uitgevoerd. - Pacerier
@Pacerier, weet je dat zeker? Of denk je dat? Niets over sorteren of zoekvolgorde wordt genoemd of gesuggereerd in de vraag. In zijn huidige vorm is de vraag niet duidelijk en kan hij op veel verschillende manieren worden geïnterpreteerd. Zonder te weten zeker wat hij vraagt, we maken aannames en bieden oplossingen die het feitelijke probleem al dan niet oplossen. Bovendien suggereert de reactie van de originele poster op een van de antwoorden dat dit zo is niet gerelateerd aan sorteren. Het heeft te maken met de betekenis van "toegevoegd en verwijderd" versus "gewijzigd". - Christopher Cashell


antwoorden:


Een andere manier om ernaar te kijken:

Toon regels die alleen in bestand a bestaan: (d.w.z. wat werd verwijderd uit a)

comm -23 a b

Toon regels die alleen in bestand b bestaan: (d.w.z. wat is toegevoegd aan b)

comm -13 a b

Toon regels die alleen in het ene of het andere bestand bestaan: (maar niet beide)

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

(Waarschuwing: indien bestand a heeft lijnen die beginnen met TAB, deze (de eerste TAB) zal van de uitvoer worden verwijderd.)

OPMERKING: Beide bestanden moeten worden gesorteerd om "comm" correct te laten werken. Als ze nog niet zijn gesorteerd, moet u ze sorteren:

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

Als de bestanden extreem lang zijn, kan dit een behoorlijke last zijn, omdat het een extra kopie vereist en dus tweemaal zoveel schijfruimte.


73
2017-09-25 18:11



wilde gewoon toevoegen dat beide bestanden moeten worden gesorteerd (hoofdlettergevoelig) voor deze oplossing om correcte resultaten te produceren - marmor
Op genoeg moderne shells kun je in de rij sorteren met zoiets comm -12 <(sort a) <(sort b) - Joshua Huber


comm zou kunnen doen wat je wilt. Van zijn manpagina:

OMSCHRIJVING

Vergelijk gesorteerde bestanden FILE1 en FILE2 regel voor regel.

Zonder opties verzendt u drie kolommen uitvoer. Kolom één   bevat regels die uniek zijn voor FILE1, kolom   twee bevat regels die uniek zijn voor FILE2,   en kolom drie bevat veel voorkomende regels   naar beide bestanden.

Deze kolommen zijn te onderdrukken met -1, -2 en -3 respectievelijk.

Voorbeeld:

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

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

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

En als u alleen de unieke lijnen wilt en het maakt niet uit in welk bestand ze zich bevinden:

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

Zoals de man-pagina zegt, moeten de bestanden van tevoren worden gesorteerd.


12
2017-09-25 14:27





Om toevoegingen en verwijderingen zonder context weer te geven, regelnummers, +, -, <,>! etc, je kunt diff als volgt gebruiken:

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

Bijvoorbeeld, gegeven twee bestanden:

a.txt

Common
Common
A-ONLY
Common

b.txt

Common
B-ONLY
Common
Common

Met de volgende opdracht worden regels weergegeven die zijn verwijderd uit een of zijn toegevoegd aan b:

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

output:

B-ONLY
A-ONLY

Deze iets andere opdracht zal de regels laten zien die verwijderd zijn uit a.txt:

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

output:

A-ONLY

Ten slotte worden met deze opdracht regels weergegeven die zijn toegevoegd aan a.txt

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

uitgang

B-ONLY

8
2018-01-05 06:41





Dat is wat diff standaard doet ... Misschien moet je een aantal vlaggen toevoegen om witruimte te negeren?

diff -b -B

zou lege regels en verschillende aantallen spaties moeten negeren.


2
2017-09-25 13:26



Nee, het toont ook GEWIJZIGDE lijnen (regels die een karakter hebben of vier verschillend). Ik wil lijnen die alleen links of rechts bestaan. - C. Ross
Je zou kunnen stellen dat de verschillende versies van een CHANGED-bestand elk alleen links of rechts bestaan. - markdrayton
Er is geen mogelijkheid voor diff (of een ander hulpmiddel) om op betrouwbare wijze te vertellen wat een wijziging is en wat een verwijderde regel wordt vervangen door een nieuwe regel. - Cian
Technisch gezien behandelt diff een "gewijzigde" regel alsof de oorspronkelijke regel was verwijderd en een nieuwe regel was toegevoegd ... dus technisch gezien toont het alleen toegevoegde en verwijderde regels. - KFro


Nee, diff toont niet echt de verschillen tussen twee bestanden op de manier waarop men zou denken. Het produceert een reeks bewerkingscommando's voor een tool zoals patch om te gebruiken om het ene bestand in het andere te veranderen.

De moeilijkheidsgraad van elke poging om te doen waar je naar op zoek bent, is hoe je kunt definiëren wat een regel is die is gewijzigd versus een verwijderde, gevolgd door een toegevoegde regel. Ook wat te doen wanneer lijnen worden toegevoegd, verwijderd en naast elkaar worden gewijzigd.


2
2017-09-25 15:59



Precies wat ik dacht. Welk percentage tekens in een regel moet worden gewijzigd om het als nieuw te beschouwen in plaats van als een wijziging van het origineel? Technisch gezien, zelfs als je één karakter gemeen hebt, zou je het een "verandering" kunnen noemen in plaats van een verwijdering en invoeging. - Kamil Kisiel
Het is lang geleden dat ik naar de diff bronnen, maar ik schijn me allerlei soorten rotaties te herinneren om bij te houden waar twee bestanden overeenkomen om synchroon te blijven en ik denk dat er een drempel is om op te geven op basis van hoe ver uit elkaar de lijnen zijn. Maar ik herinner me geen enkele intra-lijnaanpassing behalve voor (optioneel) samengevouwen witte ruimte of het negeren van hoofdletters en kleine letters. Of (misschien) woorden daarnaar beïnvloeden. In ieder geval gaat het er allemaal om patchen "vgrep" komt gewoon mee voor de rit. Kan zijn. Op dinsdag. - Dennis Williamson


Visuele vergelijkingstools passen twee bestanden aan elkaar, zodat een segment met hetzelfde aantal regels maar verschillende inhoud als een gewijzigd segment wordt beschouwd. Volledig nieuwe lijnen tussen overeenkomende segmenten worden beschouwd als toegevoegde segmenten.

Dit is ook hoe sdiff commandoregel-tool werkt, die een vergelijking van twee bestanden in een terminal naast elkaar toont. Gewijzigde regels worden gescheiden door | karakter. Als een regel alleen bestaat in bestand A, wordt <gebruikt als het scheidingsteken. Als een regel alleen in bestand B bestaat, wordt> gebruikt als scheidingsteken. Als u geen <en> tekens in de bestanden hebt, kunt u dit gebruiken om alleen toegevoegde regels weer te geven:

sdiff A B | grep '[<>]'

2
2017-10-17 14:34





Bedankt senarvi, je oplossing (niet gestemd) gaf me PRECIES precies wat ik wilde nadat ik eeuwen op een ton pagina's had gezocht.

Met behulp van uw antwoord, hier is wat ik bedacht om de lijst met dingen veranderd / toegevoegd / verwijderd te krijgen. Het voorbeeld gebruikt 2 versies van het bestand / etc / passwd en drukt de gebruikersnaam voor de relevante records af.

#!/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
2017-11-18 12:05



Merk op dat omdat het verschil tussen "een regel is gewijzigd" en "een regel is verwijderd en een ander regel is toegevoegd onder of erboven "is semantisch. Een generisch op tekst gebaseerd diff-tool kan die gevallen niet scheiden. Als gevolg daarvan kan uw op sdiff gebaseerde antwoord niet betrouwbaar voor alle gevallen werken. - Mikko Rantalainen