¿Cómo mostrar líneas en común (diff inverso)?

170

Tengo una serie de archivos de texto para los que me gustaría conocer las líneas en común en lugar de las líneas que son diferentes entre ellos. La línea de comando unix o windows está bien.

foo:

linux-vdso.so.1 =>  (0x00007fffccffe000)
libvlc.so.2 => /usr/lib/libvlc.so.2 (0x00007f0dc4b0b000)
libvlccore.so.0 => /usr/lib/libvlccore.so.0 (0x00007f0dc483f000)
libc.so.6 => /lib/libc.so.6 (0x00007f0dc44cd000)

bar:

libkdeui.so.5 => /usr/lib/libkdeui.so.5 (0x00007f716ae22000)
libkio.so.5 => /usr/lib/libkio.so.5 (0x00007f716a96d000)
linux-vdso.so.1 =>  (0x00007fffccffe000)

Entonces, dados estos dos archivos por encima de la salida de la utilidad deseada, sería similar a file1:line_number, file2:line_number == matching text (solo una sugerencia, realmente no me importa cuál es la sintaxis):

foo:1, bar:3 == linux-vdso.so.1 =>  (0x00007fffccffe000)

Gracias.

wilkie mate
fuente
@ChristopherSchultz Mi error. La primera línea del primer ejemplo se supone que coincide con la última línea del segundo ejemplo Gracias por atrapar el error; cambiando.
matt wilkie
1
Otra pregunta similar con buenas respuestas: unix.stackexchange.com/questions/1079/…
MortezaE

Respuestas:

210

En * nix, puede usar comm . La respuesta a la pregunta es:

comm -1 -2 file1.sorted file2.sorted 
# where file1 and file2 are sorted and piped into *.sorted

Aquí está el uso completo de comm:

comm [-1] [-2] [-3 ] file1 file2
-1 Suppress the output column of lines unique to file1.
-2 Suppress the output column of lines unique to file2.
-3 Suppress the output column of lines duplicated in file1 and file2. 

También tenga en cuenta que es importante ordenar los archivos antes de usar comm, como se menciona en las páginas del manual.

Dan Lew
fuente
3
comm [-1] [-2] [-3] archivo1 archivo2 -1 Suprime la columna de salida de líneas exclusivas de archivo1. -2 Suprime la columna de salida de líneas exclusivas de file2. -3 Suprime la columna de salida de líneas duplicadas en archivo1 y archivo2.
ojblass
@ojblass: se agregó esto a la respuesta.
Matt J
66
Descubrí que es importante ordenar los archivos antes de usar comm. Quizás agregue eso a la respuesta.
matt wilkie
11
respuesta corta a la pregunta: comm -1 -2
archivo1 archivo2
66
Puede usar esto si sus archivos no están ordenados: comm -1 -2 <(ordenar nombre de archivo1) <(ordenar nombre de archivo2)
Kevin Wheeler
56

Encontré esta respuesta en una pregunta que figura como duplicado . Creo que grep es más amigable para el administrador que la comunicación, por lo que si solo desea el conjunto de líneas coincidentes (por ejemplo, útil para comparar CSV) simplemente use

grep -F -x -f file1 file2

o la versión simplificada de fgrep

fgrep -xf file1 file2

Además, puede usar file2*para buscar y buscar líneas en común con múltiples archivos, en lugar de solo dos.

Algunas otras variaciones prácticas incluyen

  • -n marca para mostrar el número de línea de cada línea coincidente
  • -c para contar solo el número de líneas que coinciden
  • -vpara mostrar solo las líneas en el archivo 2 que difieren (o usan diff).

El uso commes más rápido, pero esa velocidad se produce a expensas de tener que ordenar primero los archivos. No es muy útil como 'diff inverso'.

Ryder
fuente
gracias Ryder, esto podría ser más útil que la comunicación para muchos. Debe vincular a la respuesta de origen (hay más de media docena de enlaces en Q en el navegador de la derecha; es un poco difícil de encontrar). También sería bueno saber qué tan bien hace grep con una entrada ordenada de manera diferente o diferente, y puede imprimir los números de línea de coincidencias respectivas.
Matt Wilkie
1
@mattwilkie Sentí la necesidad de volver y aclarar el uso de la -vbandera después de que yo misma me deslicé. Supongamos que tiene dos archivos csv, archivo1 y archivo2, y que tienen filas superpuestas y no superpuestas. Si desea todas y solo las filas no superpuestas, el uso fgrep -v file1 file2solo devolverá las filas no superpuestas en el archivo2, y ninguna de las filas adicionales no superpuestas en el archivo1 . Esto puede ser obvio para algunos, pero es mejor decir lo obvio que la mala interpretación del riesgo. En este caso particular, ordenar los archivos y usarlos commsigue siendo la mejor opción.
Ryder
1
Gracias por regresar y aclarar a Ryder. Se nota y aprecia la atención extra (¡todo es muy fácil dejar que las cosas viejas se escapen!). He cambiado la respuesta aceptada porque la comunicación es claramente la elección de la comunidad, aunque personalmente todavía lo uso cuando la clasificación es una sobrecarga no deseada.
Matt Wilkie
2
Otra complicación al usar grep: cualquier línea en blanco en el primer archivo coincidirá con cada línea en el segundo archivo. Asegúrese de que file1no tenga líneas en blanco, o parecerá que los archivos son idénticos.
Christopher Schultz
grep -Fxfes para mi.
loxaxs
35

Se le preguntó aquí antes: comando Unix para encontrar líneas comunes en dos archivos

También puedes probar con perl (el crédito va aquí )

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
ChristopheD
fuente
1
Gracias. Me hubiera gustado aceptar ambas respuestas, ya que el perl one liner es multiplataforma. Comm recibe el visto bueno porque es más simple.
matt wilkie
1
Perfecto. Usando el terminal cygwin en windows y commno estaba disponible. Esta fue la alternativa perfecta.
Qix - MONICA FUE MAL
3
Esto no le importa cómo se ordenan las líneas. Es más preciso que la comunicación.
enl8enmentnow
1
Una explicación está aquí: stackoverflow.com/questions/17552789/…
Chris Koknat
17

Acabo de aprender el comando de comunicación de este hilo, pero quería agregar algo extra: si los archivos no están ordenados y no desea tocar los archivos originales, puede canalizar la salida del comando de clasificación. Esto deja los archivos originales intactos. Funciona en bash, no puedo decir sobre otras conchas.

comm -1 -2 <(sort file1) <(sort file2)

Esto se puede extender para comparar la salida del comando, en lugar de los archivos:

comm -1 -2 <(ls /dir1 | sort) <(ls /dir2 | sort)
Greg Mueller
fuente
9

La forma más fácil de hacerlo es:

awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2

No es necesario ordenar los archivos.

Gopu
fuente
1
Esto es diferente a la mayoría de las respuestas aquí, ya que le permite reconstruir plantillas de origen. Tengo dos archivos creados desde el mismo contenedor, con texto diferente insertado en algunos puntos. Esta respuesta me permitió recuperar el contenedor.
Lucas Gonze
1

Solo para información, creé una pequeña herramienta para Windows que hace lo mismo que "grep -F -x -f file1 file2" (ya que no he encontrado nada equivalente a este comando en Windows)

Aquí está: http://www.nerdzcore.com/?page=commonlines

El uso es "CommonLines inputFile1 inputFile2 outputFile"

El código fuente también está disponible (GPL)

Zivilyn Bane
fuente
1

En Windows puede usar un Script Powershell con CompareObject

compare-object -IncludeEqual -ExcludeDifferent -PassThru (get-content A.txt) (get-content B.txt)> MATCHING.txt | Out-Null #Find Matching Lines

CompareObject:

  • Incluir Igual sin -ExcluirDiferente: todo
  • Excluir Diferente sin -Incluir Igual: Nada
Alcaudón
fuente