Comparar dos archivos reportar diferencia en python


Tengo 2 archivos llamados "hosts" (en diferentes directorios)

Quiero compararlos usando python para ver si son IDÉNTICOS. Si no son idénticos, quiero imprimir la diferencia en la pantalla.

Hasta ahora he intentado esto

hosts0 = open(dst1 + "/hosts","r") 
hosts1 = open(dst2 + "/hosts","r")

lines1 = hosts0.readlines()

for i,lines2 in enumerate(hosts1):
    if lines2 != lines1[i]:
        print "line ", i, " in hosts1 is different \n"
        print lines2
    else:
        print "same"

Pero cuando corro esto, obtengo

File "./audit.py", line 34, in <module>
  if lines2 != lines1[i]:
IndexError: list index out of range

Lo que significa que uno de los hosts tiene más líneas que el otro. ¿Hay un mejor método para comparar 2 archivos y reportar la diferencia?

Author: Kevin Guan, 2013-10-01

5 answers

import difflib

lines1 = '''
dog
cat
bird
buffalo
gophers
hound
horse
'''.strip().splitlines()

lines2 = '''
cat
dog
bird
buffalo
gopher
horse
mouse
'''.strip().splitlines()

# Changes:
# swapped positions of cat and dog
# changed gophers to gopher
# removed hound
# added mouse

for line in difflib.unified_diff(lines1, lines2, fromfile='file1', tofile='file2', lineterm=''):
    print line

Produce lo siguiente:

--- file1
+++ file2
@@ -1,7 +1,7 @@
+cat
 dog
-cat
 bird
 buffalo
-gophers
-hound
+gopher
 horse
+mouse

Esta diferencia le da contexto surrounding líneas circundantes para ayudar a aclarar cómo el archivo es diferente. Puede ver "gato" aquí dos veces, porque se eliminó de debajo de "perro" y se agregó por encima de él.

Puede usar n=0 para eliminar el contexto.

for line in difflib.unified_diff(lines1, lines2, fromfile='file1', tofile='file2', lineterm='', n=0):
    print line

Dando salida a esto:

--- file1
+++ file2
@@ -0,0 +1 @@
+cat
@@ -2 +2,0 @@
-cat
@@ -5,2 +5 @@
-gophers
-hound
+gopher
@@ -7,0 +7 @@
+mouse

Pero ahora está lleno de las líneas "@@" que le indican la posición en el archivo que ha cambiado. Vamos a eliminar las líneas adicionales para hacerlo más legible.

for line in difflib.unified_diff(lines1, lines2, fromfile='file1', tofile='file2', lineterm='', n=0):
    for prefix in ('---', '+++', '@@'):
        if line.startswith(prefix):
            break
    else:
        print line

Dándonos esta salida:

+cat
-cat
-gophers
-hound
+gopher
+mouse

Ahora, ¿qué quieres que haga? Si ignora todas las líneas eliminadas, entonces no verá que" hound " se eliminó. Si estás contento mostrando las adiciones al archivo, entonces puedes hacer esto:

diff = difflib.unified_diff(lines1, lines2, fromfile='file1', tofile='file2', lineterm='', n=0)
lines = list(diff)[2:]
added = [line[1:] for line in lines if line[0] == '+']
removed = [line[1:] for line in lines if line[0] == '-']

print 'additions:'
for line in added:
    print line
print
print 'additions, ignoring position'
for line in added:
    if line not in removed:
        print line

Salida:

additions:
cat
gopher
mouse

additions, ignoring position:
gopher
mouse

Probablemente ya se puede decir que hay varias formas de "imprimir las diferencias" de dos archivos, por lo que tendrá que ser muy específico si desea más ayuda.

 42
Author: rbutcher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-02 00:14:21

La biblioteca difflib es útil para esto, y viene en la biblioteca estándar. Me gusta el formato diff unificado.

Http://docs.python.org/2/library/difflib.html#difflib.unified_diff

import difflib
import sys

with open('/tmp/hosts0', 'r') as hosts0:
    with open('/tmp/hosts1', 'r') as hosts1:
        diff = difflib.unified_diff(
            hosts0.readlines(),
            hosts1.readlines(),
            fromfile='hosts0',
            tofile='hosts1',
        )
        for line in diff:
            sys.stdout.write(line)

Salidas:

--- hosts0
+++ hosts1
@@ -1,5 +1,4 @@
 one
 two
-dogs
 three

Y aquí hay una versión dudosa que ignora ciertas líneas. Puede haber casos extremos que no funcionan, y seguramente hay mejores maneras de hacer esto, pero tal vez sea lo suficientemente bueno para sus propósitos.

import difflib
import sys

with open('/tmp/hosts0', 'r') as hosts0:
    with open('/tmp/hosts1', 'r') as hosts1:
        diff = difflib.unified_diff(
            hosts0.readlines(),
            hosts1.readlines(),
            fromfile='hosts0',
            tofile='hosts1',
            n=0,
        )
        for line in diff:
            for prefix in ('---', '+++', '@@'):
                if line.startswith(prefix):
                    break
            else:
                sys.stdout.write(line[1:])
 10
Author: rbutcher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-01 16:36:33
hosts0 = open("C:path\\a.txt","r")
hosts1 = open("C:path\\b.txt","r")

lines1 = hosts0.readlines()

for i,lines2 in enumerate(hosts1):
    if lines2 != lines1[i]:
        print "line ", i, " in hosts1 is different \n"
        print lines2
    else:
        print "same"

El código anterior está funcionando para mí. ¿Puede por favor indicar a qué error se enfrenta?

 2
Author: Raj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-05 19:12:19

Puede agregar una instrucción condicional. Si su matriz va más allá del índice, rompa e imprima el resto del archivo.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-01 18:49:54
import difflib
f=open('a.txt','r')  #open a file
f1=open('b.txt','r') #open another file to compare
str1=f.read()
str2=f1.read()
str1=str1.split()  #split the words in file by default through the spce
str2=str2.split()
d=difflib.Differ()     # compare and just print
diff=list(d.compare(str2,str1))
print '\n'.join(diff)
 1
Author: Azad Mehla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-17 11:17:11