¿Cómo puedo obtener diff para mostrar solo líneas agregadas y eliminadas? Si diff no puede hacerlo, ¿qué herramienta puede?


69

¿Cómo puedo obtener diff para mostrar solo líneas agregadas y eliminadas? Si diff no puede hacerlo, ¿qué herramienta puede?


2
Necesita definir mejor lo que quiere decir con agregado y eliminado. Específicamente, ¿puede cambiar una línea? Si es así, ¿cómo desea que se maneje una línea cambiada? Si realiza una verificación estrictamente orientada a la línea, un cambio de línea es idéntico a la línea anterior que se elimina y a la nueva línea que se agrega. Por ejemplo, ¿cómo debería manejar una línea que se divide en dos? Como dos 1 línea cambió? ¿2 líneas cambiadas? ¿Se eliminó 1 línea y se agregaron 2 líneas? A menos que pueda garantizar que las líneas nunca cambiarán, solo se agregarán y eliminarán, creo que esto está condenado a fallar sin mejores definiciones.
Christopher Cashell

La pregunta me parece bastante poco clara. Pero al menos una interpretación de la pregunta podría responderse condiff A B | grep '^[<>]'
kasperd

Puede que estés buscando comm.
Jenny D dice Reinstate Monica el

@ChristopherCashell, quiere decir ignorar el orden de clasificación; Un problema típicamente común. Por lo general, esto se hace ordenando primero los segmentos (líneas) en cada lado antes de hacer una diferencia típica.
Pacerier

@Pacerier, ¿estás seguro de eso? ¿O estás adivinando? Nada sobre la clasificación o el orden de búsqueda se menciona o insinúa en la pregunta. Tal como está, la pregunta no está clara y podría interpretarse de muchas maneras diferentes. Sin saber con certeza lo que está preguntando, estamos haciendo suposiciones y ofreciendo soluciones que pueden o no resolver el problema real. Además, el comentario del póster original sobre una de las respuestas sugiere que esto no está relacionado con la clasificación. Tiene que ver con el significado de "agregado y eliminado" vs. "cambiado".
Christopher Cashell

Respuestas:


82

Prueba comm

Otra forma de verlo:

  • Mostrar líneas que solo existen en el archivo a: (es decir, lo que se eliminó de a)

    comm -23 a b
    
  • Mostrar líneas que solo existen en el archivo b: (es decir, lo que se agregó a b)

    comm -13 a b
    
  • Mostrar líneas que solo existen en un archivo u otro: (pero no en ambos)

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

(Advertencia: si el archivo atiene líneas que comienzan con TAB, se eliminará de la salida (la primera TAB).

Solo archivos ordenados

NOTA: Ambos archivos deben ser ordenados para commtrabajar correctamente. Si aún no están ordenados, debe ordenarlos:

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

Si los archivos son extremadamente largos, esto puede ser una gran carga ya que requiere una copia adicional y, por lo tanto, el doble de espacio en disco.


55
Sólo quería añadir que tanto los archivos necesita ser resuelto (mayúsculas y minúsculas) de esta solución para producir resultados correctos
Marmor

1
En conchas lo suficientemente modernas, puede ordenar en línea con algo comocomm -12 <(sort a) <(sort b)
Joshua Huber

14

commpodría hacer lo que quieras. Desde su página de manual:

DESCRIPCIÓN

Compare los archivos ordenados FILE1 y FILE2 línea por línea.

Sin opciones, produce una salida de tres columnas. La columna uno contiene líneas exclusivas de FILE1, la columna dos contiene líneas exclusivas de FILE2 y la columna tres contiene líneas comunes a ambos archivos.

Estas columnas se pueden suprimir con -1, -2y -3respectivamente.

Ejemplo:

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

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

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

Y si solo quieres las líneas únicas y no te importa en qué archivo están:

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

Como dice la página del manual, los archivos deben ordenarse de antemano.


9

Para mostrar adiciones y eliminaciones sin contexto, números de línea, +, -, <,>! etc, puedes usar diff así:

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

Por ejemplo, dados dos archivos:

a.txt

Common
Common
A-ONLY
Common

b.txt

Common
B-ONLY
Common
Common

El siguiente comando mostrará líneas eliminadas de ao agregadas a b:

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

salida:

B-ONLY
A-ONLY

Este comando ligeramente diferente mostrará líneas eliminadas de a.txt:

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

salida:

A-ONLY

Finalmente, este comando mostrará líneas agregadas a a.txt

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

salida

B-ONLY

2

Eso es lo que hace diff por defecto ... ¿Quizás necesite agregar algunas banderas para ignorar los espacios en blanco?

diff -b -B

debe ignorar líneas en blanco y diferentes números de espacios.


1
No, también muestra líneas CAMBIADAS (líneas que tienen un carácter o cuatro diferentes). Quiero líneas que solo existen en izquierda o derecha.
C. Ross el

2
Se podría argumentar que las diferentes versiones de un archivo CAMBIADO existen solo en izquierda o derecha.
markdrayton

2
No hay forma de que diff (o cualquier otra herramienta) sepa de manera confiable qué es un cambio, y qué es una línea eliminada que se reemplaza por una nueva línea.
Cian

1
Técnicamente, diff trata una línea "modificada" como si se hubiera eliminado la línea original y se hubiera agregado una nueva línea ... por lo que técnicamente solo muestra las líneas agregadas y eliminadas.
KFro

2

No, en diffrealidad no muestra las diferencias entre dos archivos en la forma en que uno podría pensar. Produce una secuencia de comandos de edición para una herramienta como patchpara cambiar un archivo a otro.

La dificultad para cualquier intento de hacer lo que está buscando es cómo definir qué constituye una línea que ha cambiado frente a una eliminada seguida de una añadida. También qué hacer cuando se agregan, eliminan y cambian líneas adyacentes entre sí.


Mis pensamientos exactamente. ¿Qué porcentaje de caracteres en una línea tiene que cambiar para considerarla nueva en lugar de una modificación del original? Técnicamente, incluso si tiene un carácter en común, podría considerarlo un "cambio" en lugar de una eliminación e inserción.
Kamil Kisiel

1
Ha pasado mucho tiempo desde que miré las difffuentes, pero parece recordar todo tipo de giros para hacer un seguimiento de dónde coinciden dos archivos para mantenerse sincronizados y creo que hay un umbral para renunciar en función de qué tan separados están las líneas son Pero no recuerdo ninguna coincidencia intralínea, excepto (opcionalmente) el espacio en blanco colapsado o el caso ignorado. O (tal vez) palabras a ese efecto. En cualquier caso, se trata de todo patchy "vgrep" simplemente aparece para el viaje. Tal vez. El martes.
Dennis Williamson

2

Las herramientas de comparación visual ajustan dos archivos juntos para que un segmento con el mismo número de líneas pero contenido diferente se considere un segmento cambiado. Las líneas completamente nuevas entre segmentos coincidentes se consideran segmentos agregados.

Así es también como funciona la herramienta de línea de comandos sdiff , que muestra una comparación lado a lado de dos archivos en un terminal. Las líneas modificadas están separadas por | personaje. Si solo existe una línea en el archivo A, <se utiliza como carácter separador. Si existe una línea solo en el archivo B,> se usa como separador. Si no tiene caracteres <y> en los archivos, puede usar esto para mostrar solo las líneas agregadas:

sdiff A B | grep '[<>]'

2

Gracias senarvi, su solución (no votada) en realidad me dio EXACTAMENTE lo que quería después de buscar años en una tonelada de páginas.

Usando su respuesta, esto es lo que se me ocurrió para cambiar / agregar / eliminar la lista de cosas. El ejemplo utiliza 2 versiones del archivo / etc / passwd e imprime el nombre de usuario para los registros relevantes.

#!/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}'

Tenga en cuenta que debido a que la diferencia entre "una línea ha sido modificada" y "una línea ha sido eliminada y otra línea ha sido agregada debajo o arriba" es semántica. Una herramienta de diferencias basada en texto genérico no puede separar esos casos. Como resultado, su respuesta basada en sdiff no puede funcionar de manera confiable para todos los casos.
Mikko Rantalainen

0

Encuentro esta forma particular a menudo útil:

diff --changed-group-format='-%<+%>' --unchanged-group-format='' f g

Ejemplo:

printf 'a\nb\nc\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

Salida:

-b
-c
+B
+C
-e
-f
+E
+F

Por lo tanto, muestra líneas antiguas -seguidas inmediatamente por la nueva línea correspondiente con +.

Si tuvimos una eliminación de C:

printf 'a\nb\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

se parece a esto:

-b
+B
+C
-e
-f
+E
+F

El formato está documentado en man diff:

       --line-format=LFMT
              format all input lines with LFMT`

y:

       LTYPE is 'old', 'new', or 'unchanged'.
              GTYPE is LTYPE or 'changed'.

y:

              LFMT (only) may contain:

       %L     contents of line

       %l     contents of line, excluding any trailing newline

       [...]

Pregunta relacionada: https://stackoverflow.com/questions/15384818/how-to-get-the-difference-only-additions-between-two-files-in-linux

Probado en Ubuntu 18.04.


-1

Archivo1:

text670_1
text067_1
text067_2

Archivo2:

text04_1
text04_2
text05_1
text05_2
text067_1
text067_2
text1000_1

Utilizar:

diff -y file1 file2

Esto muestra dos columnas para archivos de referencias.

Salida:

text670_1                           
                                  > text04_1
                                  > text04_2
                                  > text05_1
                                  > text05_2
text067_1                           text67_1
text067_2                           text67_2
                                  > text1000_1
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.