2010-12-28 17 views

Respuesta

158

diff (1) no es la respuesta, pero el comunicador (1) es.

NAME 
     comm - compare two sorted files line by line 

SYNOPSIS 
     comm [OPTION]... FILE1 FILE2 

... 

     -1  suppress lines unique to FILE1 

     -2  suppress lines unique to FILE2 

     -3  suppress lines that appear in both files 

Así

comm -2 -3 file1 file2 > file3 

Los archivos de entrada, que deben seleccionarse. Si no lo son, ordénelos primero. Esto se puede hacer con un archivo temporal, o ...

comm -2 -3 <(sort file1) <(sort file2) > file3 

siempre que su carcasa soporte la sustitución de procesos (bash does).

+0

Tenía la misma pregunta que el asker original, pero esto es exactamente lo que necesitaba. ¡Gracias! – zarose

+1

Recuerde que se deben clasificar dos archivos y es único – andy

+5

Puede agrupar las opciones en conjunto: 'comm -23' –

38

La utilidad Unix diff es para este fin.

$ diff -u file1 file2 > file3 

Consulte el manual e Internet para las opciones, diferentes formatos de salida, etc.

+7

Eso no hace el trabajo solicitado; inserta un montón de caracteres adicionales, incluso con el uso de los interruptores de línea de comando sugeridos en otras respuestas. – xenocyon

2

Uso del diff y extraer sólo las líneas que comienzan con < en la salida

6

veces diff es la utilidad lo necesita, pero a veces join es más apropiado. Los archivos deben ser ordenados previamente o, si está utilizando un shell que admite la sustitución de procesos como bash, ksh o zsh, puede hacer el orden sobre la marcha.

join -v 1 <(sort file1) <(sort file2) 
14

Considera:
archivo a.txt:

abcd 
efgh 

archivo b.txt:

abcd 

puede encontrar la diferencia con:

diff -a --suppress-common-lines -y a.txt b.txt 

La salida w La enfermedad sea:

efgh 

Usted puede redirict la salida en un archivo de salida (c.txt) usando:

diff -a --suppress-common-lines -y a.txt b.txt > c.txt 

Esto responder a su pregunta:

" ... lo cual contiene las líneas en el archivo1 que son no presentes en el archivo2. "

+2

Hay dos limitaciones a esta respuesta: (1) solo funciona para líneas cortas (menos de 80 caracteres por defecto, aunque esto puede modificarse) y, más importante, (2) agrega un "<" al final de cada línea que se debe quitar con otro programa (por ejemplo, awk, sed). – sergut

+0

En muchos casos, también querrás usar '-d', lo que hará que' diff'do sea el mejor para encontrar la diferencia más pequeña posible. '-i',' -E', '-w',' -B' y '--suppress-blank-empty' también pueden ser útiles ocasionalmente, aunque no siempre.Si no sabes qué se ajusta a tu caso de uso, prueba con 'diff --help' primero (que generalmente es una buena idea cuando no sabes lo que puede hacer un comando). –

+0

Además, al usar --line-format =% L, no puedes generar caracteres adicionales (al menos, la ayuda dice que funciona así, pero a punto de probarlo). –

2

Trate

sdiff file1 file2 

Se ususally funciona mucho mejor en la mayoría de los casos para mí. Es posible que desee ordenar archivos antes, si el orden de las líneas no es importante (por ejemplo, algunos archivos de configuración de texto).

Por ejemplo,

sdiff -w 185 file1.cfg file2.cfg 
+1

¡Buena utilidad! Me encanta cómo marca las líneas diferenciadoras. Hace que sea mucho más fácil comparar configuraciones. Esto junto con sort es un combo mortal (por ejemplo, 'sdiff <(sort file1) <(sort file2)') – jmagnusson

2

muchos ya respuestas, pero ninguno de ellos en mi humilde opinión perfecta. La respuesta de Thanatos deja algunos caracteres adicionales por línea y la respuesta de Sorpigal requiere que los archivos sean ordenados o pre-ordenados, lo que puede no ser adecuado en todas las circunstancias.

Creo que la mejor manera de obtener las líneas que son diferentes y nada más (no hay caracteres adicionales, sin volver a realizar el pedido) es una combinación de diff, grep y awk (o similar).

Si las líneas no contienen ninguna "<", un corto de una sola línea puede ser:

diff urls.txt* | grep "<" | sed 's/< //g' 

pero que eliminará todos los casos de "<" (menor que, el espacio) de las líneas, que no siempre está bien (por ejemplo, el código fuente). La opción más segura es usar awk:

diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}' 

Este de una sola línea diffs ambos archivos, a continuación, filtra la salida de estilo ed de diff, a continuación, elimina el arrastre "<" que añade diff. Esto funciona incluso si las líneas contienen algunos "<" ellos mismos.

+1

comm no requiere clasificación (en versiones más nuevas?) - solo use --nocheck-order. Utilizo esto mucho al manipular csvs desde la CLI – ak5

2

Si tiene que resolver esto con coreutils la respuesta aceptada es buena:

comm -23 <(sort file1) <(sort file2) > file3 

Puede también utilizar sd (esta corriente), que no requiere la clasificación ni la sustitución de procesos y soporta flujos infinitos, como Entonces:

cat file1 | sd 'cat file2' > file3 

Probablemente no sea tan beneficioso en este ejemplo, pero considérelo; en algunos casos, no podrá usar comm ni grep -F ni diff.

Aquí hay un blogpost que escribí sobre transmisiones difusas en el terminal, que presenta sd.

1
diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt 

Intenté casi todas las respuestas en este hilo, pero ninguna fue completa. Después de algunos senderos arriba uno funcionó para mí. diff le dará la diferencia, pero con algunas charas especiales no deseados. donde las líneas de diferencias reales comienzan con '>'. así que el siguiente paso es grep líneas comienza con '>' y luego se elimina con sed.

+0

. Esta es una mala idea. También necesitarías modificar líneas comenzando con '<'. Verá esto si intercambia el orden de los archivos de entrada. Incluso si hicieras esto, querrías omitir 'grep' al usar más sed:' diff a1 a2 | sed '/>/s ///' 'Esto aún puede romper líneas que contengan'> 'o' <'en la situación correcta y ** todavía ** deja líneas adicionales que describen los números de línea. Si quisiera probar este enfoque, una mejor manera sería: 'diff -C0 a1 a2 | sed -ne '/^[+ -]/s /^..// p''. – Sorpigal

Cuestiones relacionadas