Eine alte und eine neue Datei vergleichen, aber Zeilen ignorieren, die nur in einer neuen Datei vorhanden sind?

7

Ich habe zwei Dateien:

  1. oldlist- Diese enthält eine Liste von Dateien und einen MD5-Hash für jede Datei. Dies wurde vor einem Jahr generiert.
  2. newlist- Dies enthält auch eine Liste von Dateien und einen MD5-Hash für jede Datei. Einige Dateien wurden jedoch geändert (z. B. der MD5-Hash ist anders), und einige neue Dateien wurden hinzugefügt.

Ich würde gerne alle Unterschiede zwischen oldlistund sehen newlist, aber ich möchte alle Dateien ignorieren, in denen es keine gibt oldlist.

Das heißt, neue Dateien interessieren mich nicht. Ich möchte nur die md5-Hashes für jede alte Datei vergleichen, damit ich sehen kann, ob sich Dateien im letzten Jahr geändert haben.

Ich habe diff und comm ausprobiert , aber noch keine Lösung gefunden.

Stefan Lasiewski
quelle

Antworten:

5

Verwenden Sie joindiese Option , um übereinstimmende Zeilen aus den beiden Dateien zu kombinieren. Angenommen, die Dateinamen kommen nach den Prüfsummen (wie in der md5sumAusgabe) und enthalten keine Leerzeichen, werden alle in beiden Listen vorhandenen Dateinamen zusammen mit der alten Prüfsumme und der neuen Prüfsumme gedruckt:

join -1 2 -2 2 <(sort -k 2 oldlist) <(sort -k 2 newlist)

Übergeben Sie die -aOption an , um auch neue Dateien anzuzeigen join. Durch ein wenig Nachbearbeitung der Ausgabe werden die Dateinamen entfernt, für die sich die Prüfsumme nicht geändert hat.

join -a 2 -1 2 -2 2 <(sort -k 2 oldlist) <(sort -k 2 newlist) |
awk '$2 != $3'
Gilles 'SO - hör auf böse zu sein'
quelle
3

Du könntest es awkalleine machen:

$ awk 'FNR==NR   { o[$2]=$1; next }       !o[$2] { print $0, "NEW"; next } 
       $1!=o[$2] { print $0, "CHANGED" }' newlist oldlist

(Beachten Sie, dass das angenommene Format der Dateien md5sumdas Ausgabeformat ist: "md5 Dateiname".)

Update : Schrittweise Erklärung der Funktionsweise dieses awkEinzeilers.

awk 'FNR==NR { # if current record number==overall record number (still processing the first file)
  o[$2]=$1     # store the record in array o: the key is the file name, the value is the md5
  next         # go to next record (do not execute the rest of the code)
}
# reaching this point means we are processing the second input file
!o[$2] {       # if array o not contains item with the current record`s file name
  print $0, "NEW" # print the current record and specify that it`s new
  next         # go to next record (do not execute the rest of the code)
}
# reaching this point means array o contains item with the current file name
$1!=o[$2] {    # if the current md5 is not equal with the md5 save for the current file name
  print $0, "CHANGED" # print the current record and specify it`s changed
}' newlist oldlist
Mann bei der Arbeit
quelle
nette Antwort, macht es Ihnen etwas aus, eine kleine Erklärung des awk-Programms hinzuzufügen? Zum Beispiel, dass FNR == NR verhindert, dass die Aktion auf die 2. Datei usw.
angewendet wird
@maxschlepzig, ich habe die Erklärung hinzugefügt. Falls es nicht den SO-Standards und Erwartungen entspricht, bin ich offen für Vorschläge zur Aktualisierung.
Manatwork
3

Wenn ich Ihre Frage richtig verstanden hätte, könnte ich commtatsächlich tun, was Sie wollen. Ich würde vorschlagen, nachzuschauencomm --help

spezifisch

  -1              suppress column 1 (lines unique to FILE1)
  -2              suppress column 2 (lines unique to FILE2)
  -3              suppress column 3 (lines that appear in both files)

so comm newFile oldFile -1 -3wird das tun , was Sie wollen.

Sirex
quelle
1

Angenommen, die Dateien sehen aus wie (durch Leerzeichen getrennt):

file1 md5sum1
file2 md5sum2

Einfache Lösung:

# get only the files:
cut -f 1 -d " " oldlist > oldlist.files 

# from newlist, take only files which were also in the oldlist (updated files)
grep -w -F -f oldlist.files newlist > newlist.updated_files

Und dann können Sie einfach die beiden Dateien vergleichen (nach dem Sortieren):

sort -u oldlist > oldlist.su
sort -u newlist.updated_files > newlist.updated_files.su
diff oldlist.su newlist.updated_files.su
Tomas
quelle
1

Nur als Alternative habe ich immer " sdiff -s" zum Vergleichen von Dateilisten oder MD5-Summen verwendet.

Angenommen, die Dateien sind normale md5sum-Ausgaben " md5hash filename". Dann entweder:

sdiff -s oldfile newfile | grep -v ">"
# sorting on the md5hash should help align and pick up renamed files.
sdiff -s <(sort oldfile) <(sort newfile)

Brechen diese nach unten:
sdiff -s: supress gemeinsamen Leitungen sind so exakte Übereinstimmungen ignoriert. Shows |, <, >für Unterschiede.
<(sort oldfile): sortiert den Befehl vor dem sdiff.
grep -v ">": Neue Dateieinträge ignorieren. Funktioniert nur, wenn Sie keinen >Dateinamen haben, was ohnehin unwahrscheinlich ist.

Die Breite von sdiffkann geändert werden, um längere Linien anzuzeigen -w 100.

Matt
quelle