2012-04-26 18 views
9

Probablemente esta es una pregunta muy básica para los programadores de shell. Pero supongamos que tengo un archivo de texto A y B y B es un subconjunto de A.programación básica de shell

Quiero crear un archivo de texto C que contiene datos (A-B).

omita todas las líneas comunes.

La línea en los archivos de datos numéricos son: como

id , some aspect, other aspec. 

Gracias.

+0

No ha mencionado, de cualquier manera, ya sea o no sus datos pueden contener líneas duplicadas. Si puede, tenga en cuenta que el método 'sort' +' uniq' de Tim Pote ** no funciona ** cuando hay líneas duplicadas sin igual en 'A'. Los métodos 'awk' y' comm' funcionan con duplicados en 'A'. –

Respuesta

12

Uso sort y uniq

sort a b | uniq -u 

Si desea que las líneas que son iguales entre A y B, puede utilizar uniq -d

sort a b | uniq -d 

Esto supone, por supuesto, que los datos de A y B son exactamente lo mismo. No puede haber espacios o pestañas perdidos en los conjuntos de datos. Si los hay, primero deberá limpiar los datos con sed, tr o awk.

Edición

Como Pedro. O señaló, esto fallará si hay duplicados exactos en el archivo a. Si eso es un problema, se puede fijar al hacer esto:

sort <(sort -u a) b | uniq -u 
+0

una pregunta muy ingenua. ¿Cómo lo guardo en el archivo "c"? – Fraz

+1

Necesita redirigir la salida con '>'.Entonces el comando sería: 'ordenar a b | uniq -u> c' –

+1

'ordenar a b | uniq -u> c' – dpp

4

Una forma usando awk. Redirigir para guardar contenido en cualquier archivo en lugar de STDOUT.

awk 'FNR == NR { data[ $0 ] = 1; next } FNR < NR { if ($0 in data) { next } print $0 }' fileB fileA 

ACTUALIZADO con un comando más eficiente. Gracias a Peter.O:

awk 'FNR==NR{data[$0]; next}; $0 in data{next}; 1' fileB fileA 
+0

Solo unos pocos puntos para hacer un poco más consise (y más rápido): 1) No es necesario asignar un valor a la matriz; solo al hacer referencia crea la porción de índice. 2) La segunda prueba de FNR no es necesaria, ya que el 'siguiente' anterior se ocupa de eso. 3) La prueba 'si' es superflua, ya que' $ 0 en datos' es una prueba en sí misma. 4) Cualquier valor distinto de cero hará que '$ 0' se imprima, por lo que' print $ 0' puede ser un "valor booleano": 'awk 'FNR == NR {data [$ 0]; siguiente}; $ 0 en datos {siguiente}; 1 'fileB fileA' –

+0

@ Peter.O: Gracias por las sugerencias. Añado tu comando a la respuesta. – Birei

+0

Tampoco necesita esas declaraciones nulas (puntos y comas) y en lugar de probar $ 0 en datos y hacer luego, y luego tiene una impresión implícita después, puede negar la prueba y no necesita la primera siguiente (a menos que el archivo B sea enorme y la eficiencia sea un problema) por lo que puede escribirlo como 'awk 'FNR == NR {datos [$ 0]}! ($ 0 en datos}' archivoB archivoA'. –

7

Hay una utilidad llamada comm que se utiliza para esto:

comm -23 A B > C 

donde -2 significa "rechazan las líneas únicas para presentar B" (que dicen que hay aren 't any), y -3 significa "rechazar las líneas comunes a ambos archivos".

@BartonChittenden hace un buen punto:

comm -23 <(sort A) <(sort B) > C 
+2

Tenga en cuenta que ambos archivos deben estar ordenados. –

+0

+1 por mostrarme 'comm', que nunca había escuchado. +10 por mostrarme' <(comando) 'que tampoco había escuchado nunca. –

+1

Esto se llama" sustitución de procesos "y le permite tratar el Salida de un comando como si fuera un archivo. Consulte la página de manual. –

2
awk 'FNR==NR{a[$0];next}(!($0 in a))' B A